Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,684 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
'''
This file can be loaded into GDB to improve the debugging experience.
It has the following features:
* Pretty printers for various types like `blender::Map` and `blender::IndexMask`.
* Frame filters to reduce the complexity of backtraces.
The basic setup is simple. Add the following line to a `~/.gdbinit` file.
Everything in this file is run by GDB when it is started.
```
source ~/blender-git/blender/tools/debug/gdb/blender_gdb_extension.py
```
To validate that things are registered correctly:
1. Start `gdb`.
2. Run `info pretty-printer` and check for `blender-pretty-printers`.
3. Run `info frame-filter` and check for `blender-frame-filters`.
'''
__all__ = (
# Not used externally but functions as a `main`.
"register",
)
import gdb
import gdb.printing
from contextlib import contextmanager
from gdb.FrameDecorator import FrameDecorator
@contextmanager
def eval_var(variable_name, value):
'''
Creates a context in which the given variable name has the given value.
'''
gdb.set_convenience_variable(variable_name, value)
try:
yield
finally:
gdb.set_convenience_variable(variable_name, None)
@contextmanager
def ensure_unwind_on_signal():
'''
Creates a context in which gdb can attempt evaluating functions with
less risk of crashing the program. If there is an error (e.g. a segfault)
gdb will unwind the stack, raise a Python exception, but otherwise allows
continuing the debugging session.
'''
was_on = "is on." in gdb.execute("show unwindonsignal", to_string=True)
if not was_on:
gdb.execute("set unwindonsignal on")
try:
yield
finally:
if not was_on:
gdb.execute("set unwindonsignal off")
class VectorPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
vec_begin = self.value["begin_"]
vec_end = self.value["end_"]
vec_capacity_end = self.value["end_"]
vec_size = vec_end - vec_begin
vec_capacity = vec_capacity_end - vec_begin
return f"Size: {vec_size}"
def children(self):
begin = self.value["begin_"]
end = self.value["end_"]
size = end - begin
for i in range(size):
yield str(i), begin[i]
def display_hint(self):
return "array"
class SetPrinter:
def __init__(self, value: gdb.Value):
self.value = value
self.key_type = value.type.template_argument(0)
def to_string(self):
size = int(
self.value["occupied_and_removed_slots_"] - self.value["removed_slots_"]
)
return f"Size: {size}"
def children(self):
slots = self.value["slots_"]["data_"]
slots_num = int(self.value["slots_"]["size_"])
for i in range(slots_num):
slot = slots[i]
if self.key_type.code == gdb.TYPE_CODE_PTR:
key = slot["key_"]
key_int = int(key)
# The key has two special values for an empty and removed slot.
is_occupied = key_int < 2**64 - 2
if is_occupied:
yield str(i), key
else:
slot_state = int(slot["state_"])
is_occupied = slot_state == 1
if is_occupied:
key = slot["key_buffer_"].cast(self.key_type)
yield str(i), key
def display_hint(self):
return "array"
class MapPrinter:
def __init__(self, value: gdb.Value):
self.value = value
self.key_type = value.type.template_argument(0)
self.value_type = value.type.template_argument(1)
def to_string(self):
size = int(
self.value["occupied_and_removed_slots_"] - self.value["removed_slots_"]
)
return f"Size: {size}"
def children(self):
slots = self.value["slots_"]["data_"]
slots_num = int(self.value["slots_"]["size_"])
for i in range(slots_num):
slot = slots[i]
if self.key_type.code == gdb.TYPE_CODE_PTR:
key = slot["key_"]
key_int = int(key)
# The key has two special values for an empty and removed slot.
is_occupied = key_int < 2**64 - 2
if is_occupied:
value = slot["value_buffer_"].cast(self.value_type)
yield "Key", key
yield "Value", value
else:
slot_state = int(slot["state_"])
is_occupied = slot_state == 1
if is_occupied:
key = slot["key_buffer_"].cast(self.key_type)
value = slot["value_buffer_"].cast(self.value_type)
yield "Key", key
yield "Value", value
def display_hint(self):
return "map"
class MultiValueMapPrinter:
def __init__(self, value: gdb.Value):
self.value = value
self.map_value = value["map_"]
def to_string(self):
return MapPrinter(self.map_value).to_string()
def children(self):
return MapPrinter(self.map_value).children()
def display_hint(self):
return MapPrinter(self.map_value).display_hint()
class TypedBufferPrinter:
def __init__(self, value: gdb.Value):
self.value = value
self.type = value.type.template_argument(0)
self.size = value.type.template_argument(1)
def children(self):
data = self.value.cast(self.type).address
for i in range(self.size):
yield str(i), data[i]
def display_hint(self):
return "array"
class ArrayPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
size = self.value["size_"]
return f"Size: {size}"
def children(self):
data = self.value["data_"]
size = self.value["size_"]
for i in range(size):
yield str(i), data[i]
def display_hint(self):
return "array"
class VectorSetPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def get_size(self):
return int(
self.value["occupied_and_removed_slots_"] - self.value["removed_slots_"]
)
def to_string(self):
size = self.get_size()
return f"Size: {size}"
def children(self):
data = self.value["keys_"]
size = self.get_size()
for i in range(size):
yield str(i), data[i]
def display_hint(self):
return "array"
class VArrayPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def get_size(self):
impl = self.value["impl_"]
size = int(impl["size_"])
return size
def to_string(self):
size = self.get_size()
with eval_var("varray", self.value.address):
is_single = gdb.parse_and_eval("$varray->is_single()")
if is_single and size >= 1:
with eval_var("varray", self.value.address):
single_value = gdb.parse_and_eval("$varray->get_internal_single()")
return f"Size: {size}, Single Value: {single_value}"
return f"Size: {size}"
def children(self):
size = self.get_size()
impl = self.value["impl_"]
for i in range(size):
with eval_var("varray_impl", impl):
value_at_index = gdb.parse_and_eval(f"$varray_impl->get({i})")
yield str(i), value_at_index
def display_hint(self):
return "array"
class MathVectorPrinter:
def __init__(self, value: gdb.Value):
self.value = value
self.base_type = value.type.template_argument(0)
self.size = value.type.template_argument(1)
def to_string(self):
values = [str(self.get(i)) for i in range(self.size)]
return "(" + ", ".join(values) + ")"
def children(self):
for i in range(self.size):
yield str(i), self.get(i)
def get(self, i):
# Avoid taking pointer of value in case the pointer is not available.
if 2 <= self.size <= 4:
if i == 0:
return self.value["x"]
if i == 1:
return self.value["y"]
if i == 2:
return self.value["z"]
if i == 3:
return self.value["w"]
return self.value["values"][i]
def display_hint(self):
return "array"
class SpanPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
size = self.value["size_"]
return f"Size: {size}"
def children(self):
data = self.value["data_"]
size = self.value["size_"]
for i in range(size):
yield str(i), data[i]
def display_hint(self):
return "array"
class StringRefPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
data = self.value["data_"]
size = int(self.value["size_"])
if size == 0:
return ""
return data.string(length=size)
def display_hint(self):
return "string"
class IndexRangePrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
start = int(self.value["start_"])
size = int(self.value["size_"])
if size == 0:
return "Size: 0"
return f"Size: {size}, [{start} - {start + size - 1}]"
def display_hint(self):
return None
class IndexMaskPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
size = int(self.value["indices_num_"])
if size == 0:
return "Size: 0"
segments_num = int(self.value["segments_num_"])
with eval_var("mask", self.value.address):
first = int(gdb.parse_and_eval("$mask->first()"))
last = int(gdb.parse_and_eval("$mask->last()"))
is_range = last - first + 1 == size
if is_range:
return f"Size: {size}, [{first} - {last}], Segments: {segments_num}"
return f"Size: {size}, Segments: {segments_num}"
def children(self):
segments_num = int(self.value["segments_num_"])
prev_cumulative_size = int(self.value["cumulative_segment_sizes_"][0])
for segment_i in range(segments_num):
cumulative_size = int(
self.value["cumulative_segment_sizes_"][segment_i + 1]
)
full_segment_size = cumulative_size - prev_cumulative_size
indices_ptr = self.value["indices_by_segment_"][segment_i]
offset = self.value["segment_offsets_"][segment_i]
with eval_var("mask", self.value.address):
segment = gdb.parse_and_eval(f"$mask->segment({segment_i})")
yield str(segment_i), segment
prev_cumulative_size = cumulative_size
def display_hint(self):
return "array"
class IndexMaskSegmentPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
size = int(self.value["data_"]["size_"])
if size == 0:
return "Size: 0"
offset = int(self.value["offset_"])
first = int(self.value["data_"]["data_"][0]) + offset
last = int(self.value["data_"]["data_"][size - 1]) + offset
is_range = last - first + 1 == size
if is_range:
return f"Size: {size}, [{first} - {last}]"
return f"Size: {size}"
def children(self):
size = int(self.value["data_"]["size_"])
offset = int(self.value["offset_"])
for i in range(size):
element = int(self.value["data_"]["data_"][i])
index = element + offset
yield str(i), index
def display_hint(self):
return "array"
class OffsetIndicesPrinter:
def __init__(self, value: gdb.Value):
self.value = value
def to_string(self):
with eval_var("indices", self.value.address):
size = gdb.parse_and_eval("$indices->size()")
return f"Size: {size}"
def children(self):
with eval_var("indices", self.value.address):
size = gdb.parse_and_eval("$indices->size()")
for i in range(size):
with eval_var("indices", self.value.address):
element = gdb.parse_and_eval(f"(*$indices)[{i}]")
yield str(i), element
def display_hint(self):
return "array"
class ErrorHandlingPrinter:
'''
This class can wrap another printer and adds additional error handling on top.
'''
def __init__(self, printer):
self.printer = printer
def to_string(self):
try:
with ensure_unwind_on_signal():
return self.printer.to_string()
except Exception as ex:
return f"Error: {ex!s}"
def children(self):
try:
children_generator = self.printer.children()
while True:
with ensure_unwind_on_signal():
next_child = next(children_generator)
yield next_child
except:
return
def display_hint(self):
return self.printer.display_hint()
class BlenderPrettyPrinters(gdb.printing.PrettyPrinter):
def __init__(self):
super().__init__("blender-pretty-printers")
def get_pretty_printer(self, value: gdb.Value):
value_type = value.type
if value_type is None:
return None
if value_type.code == gdb.TYPE_CODE_PTR:
return None
type_name = value_type.strip_typedefs().name
if type_name is None:
return None
if type_name.startswith("blender::Vector<"):
return VectorPrinter(value)
if type_name.startswith("blender::Set<"):
return SetPrinter(value)
if type_name.startswith("blender::Map<"):
return MapPrinter(value)
if type_name.startswith("blender::MultiValueMap<"):
return MultiValueMapPrinter(value)
if type_name.startswith("blender::TypedBuffer<"):
return TypedBufferPrinter(value)
if type_name.startswith("blender::Array<"):
return ArrayPrinter(value)
if type_name.startswith("blender::VectorSet<"):
return VectorSetPrinter(value)
if type_name.startswith("blender::VArray<"):
return VArrayPrinter(value)
if type_name.startswith("blender::VMutableArray<"):
return VArrayPrinter(value)
if type_name.startswith("blender::VecBase<"):
return MathVectorPrinter(value)
if type_name.startswith("blender::Span<"):
return SpanPrinter(value)
if type_name.startswith("blender::MutableSpan<"):
return SpanPrinter(value)
if type_name.startswith("blender::VArraySpan<"):
return SpanPrinter(value)
if type_name == "blender::StringRef":
return StringRefPrinter(value)
if type_name == "blender::StringRefNull":
return StringRefPrinter(value)
if type_name == "blender::IndexRange":
return IndexRangePrinter(value)
if type_name == "blender::index_mask::IndexMask":
return IndexMaskPrinter(value)
if type_name in (
"blender::OffsetSpan<long, short>",
"blender::index_mask::IndexMaskSegment",
):
return IndexMaskSegmentPrinter(value)
if type_name.startswith("blender::offset_indices::OffsetIndices<"):
return OffsetIndicesPrinter(value)
return None
def __call__(self, value: gdb.Value):
if printer := self.get_pretty_printer(value):
return ErrorHandlingPrinter(printer)
return None
class ForeachIndexFilter:
filename_pattern = r".*index_mask.*"
@staticmethod
def frame_to_name(frame):
function_name = frame.function()
if function_name.startswith("blender::index_mask::IndexMask::foreach_index"):
return "Foreach Index"
class LazyFunctionEvalFilter:
filename_pattern = r".*functions.*lazy_function.*"
@staticmethod
def frame_to_name(frame):
function_name = frame.function()
if function_name.startswith((
"blender::fn::lazy_function::LazyFunction::execute",
"blender::fn::lazy_function::Executor::push_to_task_pool",
)):
return "Execute Lazy Function"
class ThreadingFilter:
filename_pattern = (
r".*(include/tbb|libtbb|task_pool.cc|BLI_task.hh|task_range.cc).*"
)
@staticmethod
def frame_to_name(frame):
function_name = frame.function()
if function_name.startswith("BLI_task_pool_work_and_wait"):
return "Task Pool work and wait"
if function_name.startswith(
"tbb::internal::rml::private_worker::thread_routine"
):
return "TBB Worker Thread"
if function_name.startswith("blender::threading::parallel_for"):
return "Parallel For"
if function_name.startswith("blender::threading::isolate_task"):
return "Isolate Task"
class StdFilter:
filename_pattern = r".*/include/c\+\+/13.*"
@staticmethod
def frame_to_name(frame):
function_name = frame.function()
if function_name.startswith("std::function") and "operator()" in function_name:
return "Call std::function"
class FunctionRefFilter:
filename_pattern = r".*BLI_function_ref.hh"
@staticmethod
def frame_to_name(frame):
function_name = frame.function()
if "operator()" in function_name:
return "Call FunctionRef"
frame_filters = [
ForeachIndexFilter(),
LazyFunctionEvalFilter(),
ThreadingFilter(),
StdFilter(),
FunctionRefFilter(),
]
class FrameFilter:
def __init__(self):
self.name = "blender-frame-filters"
self.priority = 100
self.enabled = True
def filter(self, frame_iter):
import re
current_filter = None
current_frames = []
def handle_gathered_frames():
nonlocal current_frames
nonlocal current_filter
if current_frames:
top_frame = current_frames[-1]
bottom_frame = current_frames[0]
name = current_filter.frame_to_name(top_frame)
if name is None:
yield from current_frames
else:
yield SimpleFrameDecorator(name, bottom_frame, current_frames[1:])
current_frames = []
current_filter = None
for frame in frame_iter:
file_name = frame.filename()
if file_name is None:
yield frame
continue
if current_filter and re.match(
current_filter.filename_pattern, file_name
):
current_frames.append(frame)
continue
yield from handle_gathered_frames()
for f in frame_filters:
if re.match(f.filename_pattern, file_name):
current_filter = f
current_frames = [frame]
break
else:
yield frame
yield from handle_gathered_frames()
class SimpleFrameDecorator(FrameDecorator):
def __init__(self, name, frame, elided_frames):
super().__init__(frame)
self.name = name
self.frame = frame
self.elided_frames = elided_frames
def elided(self):
return iter(self.elided_frames)
def function(self):
return self.name
def frame_args(self):
return None
def address(self):
return None
def line(self):
return None
def filename(self):
return None
def frame_locals(self):
return None
def register():
gdb.printing.register_pretty_printer(None, BlenderPrettyPrinters(), replace=True)
frame_filter = FrameFilter()
gdb.frame_filters[frame_filter.name] = frame_filter
if __name__ == "__main__":
register()

View File

@@ -0,0 +1 @@
This folder contains (incomplete) type hints for the `gdb` [Python API](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html). This simplifies working with the API.

View File

@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .gdb import *
import printing
import types

View File

@@ -0,0 +1,224 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from __future__ import annotations
import enum
from collections.abc import (
Sequence,
)
# Does not actually exist.
class TypeCode:
pass
TYPE_CODE_PTR: TypeCode
TYPE_CODE_ARRAY: TypeCode
TYPE_CODE_STRUCT: TypeCode
TYPE_CODE_UNION: TypeCode
TYPE_CODE_ENUM: TypeCode
TYPE_CODE_FLAGS: TypeCode
TYPE_CODE_FUNC: TypeCode
TYPE_CODE_INT: TypeCode
TYPE_CODE_FLT: TypeCode
TYPE_CODE_VOID: TypeCode
TYPE_CODE_SET: TypeCode
TYPE_CODE_RANGE: TypeCode
TYPE_CODE_STRING: TypeCode
TYPE_CODE_BITSTRING: TypeCode
TYPE_CODE_ERROR: TypeCode
TYPE_CODE_METHOD: TypeCode
TYPE_CODE_METHODPTR: TypeCode
TYPE_CODE_MEMBERPTR: TypeCode
TYPE_CODE_REF: TypeCode
TYPE_CODE_RVALUE_REF: TypeCode
TYPE_CODE_CHAR: TypeCode
TYPE_CODE_BOOL: TypeCode
TYPE_CODE_COMPLEX: TypeCode
TYPE_CODE_TYPEDEF: TypeCode
TYPE_CODE_NAMESPACE: TypeCode
TYPE_CODE_DECFLOAT: TypeCode
TYPE_CODE_INTERNAL_FUNCTION: TypeCode
class Objfile:
pass
class Type:
alignof: int
sizeof: int
code: TypeCode
dynamic: bool
name: str | None
tag: str | None
objfile: Objfile | None
def fields(self) -> list[Field]:
pass
def array(self, n1, n2=None) -> Type:
pass
def vector(self, n1, n2=None) -> Type:
pass
def const(self) -> Type:
pass
def volatile(self) -> Type:
pass
def unqualified(self) -> Type:
pass
def range(self):
pass
def reference(self) -> Type:
pass
def pointer(self) -> Type:
pass
def strip_typedefs(self) -> Type:
pass
def target(self) -> Type:
pass
def template_argument(self, n, block=None) -> type | Value:
pass
def optimized_out(self) -> Value:
pass
class Field:
bitpos: int
enumval: int
name: str | None
artificial: bool
is_base_class: bool
bitsize: int
type: Type
parent_type: Type
class Value:
type: Type
address: Value | None
is_optimized_out: bool
dynamic_type: Type
is_lazy: bool
def dereference(self) -> Value:
pass
def referenced_value(self) -> Value:
pass
def reference_value(self) -> Value:
pass
def const_value(self) -> Value:
pass
def format_string(self, *args, **kwargs) -> str:
pass
def string(self, encoding=None, errors=None, length=None) -> str:
pass
def lazy_string(self, encoding=None, length=None) -> str:
pass
def fetch_lazy(self):
pass
def cast(self, type: Type) -> Value:
pass
def reinterpret_cast(self, type: Type) -> Value:
pass
def __getitem__(self, subscript: int | str) -> Value:
pass
def lookup_type(name: str, block=None) -> Type:
pass
def lookup_global_symbol(name: str):
pass
def execute(command: str, from_tty=None, to_string=None):
pass
def parse_and_eval(expression: str) -> Value:
pass
def set_convenience_variable(name: str, value: Value):
pass
def convenience_variable(name: str) -> Value | None:
pass
class MemoryError(Exception):
pass
class Command:
def __init__(self, name, command_class, complete_class=None, prefix=None):
pass
def dont_repeat(self):
pass
def invoke(self, argument: str, from_tty: bool):
pass
def complete(self, text: str, word: str) -> Sequence[str] | CompleteCode:
pass
# Does not actually exist.
class CommandCode:
pass
COMMAND_NONE: CommandCode
COMMAND_RUNNING: CommandCode
COMMAND_DATA: CommandCode
COMMAND_STACK: CommandCode
COMMAND_FILES: CommandCode
COMMAND_SUPPORT: CommandCode
COMMAND_STATUS: CommandCode
COMMAND_BREAKPOINTS: CommandCode
COMMAND_TRACEPOINTS: CommandCode
COMMAND_TUI: CommandCode
COMMAND_USER: CommandCode
COMMAND_OBSCURE: CommandCode
COMMAND_MAINTENANCE: CommandCode
# Does not actually exist.
class CompleteCode:
pass
COMPLETE_NONE: CompleteCode
COMPLETE_FILENAME: CompleteCode
COMPLETE_LOCATION: CompleteCode
COMPLETE_COMMAND: CompleteCode
COMPLETE_SYMBOL: CompleteCode
COMPLETE_EXPRESSION: CompleteCode

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from .gdb import Value
class PrettyPrinter:
def __init__(self, name: str, subprinters=None):
pass
def __call__(self, value: Value):
pass

View File

@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
from gdb import Type, Field
def get_basic_type(type: Type) -> Type:
pass
def has_field(type: Type) -> bool:
pass
def make_enum_dict(enum_type: Type) -> dict[str, int]:
pass

View File

@@ -0,0 +1,122 @@
# SPDX-FileCopyrightText: 2026 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
"""
LLDB pretty printer for Blender types
Add to ~/.lldbinit:
command script import {path-to-blender-source}/tools/debug/lldb/blender_lldb_formatter.py
If using CodeLLDB extension for VSCode this needs to be added to the user or workspace settings.json:
"lldb.launch.initCommands": [ "command source ${env:HOME}/.lldbinit" ]
"""
import lldb
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
'type summary add -x "^blender::VecBase<" -F blender_lldb_formatter.math_vector_SummaryProvider'
)
debugger.HandleCommand(
'type synthetic add -x "^blender::(float|double)(2|3|4)x(2|3|4)$" -l blender_lldb_formatter.math_matrix_SyntheticProvider'
)
debugger.HandleCommand(
'type synthetic add -x "^blender::Vector<" -l blender_lldb_formatter.bli_vector_SyntheticProvider'
)
def math_vector_SummaryProvider(valobj, internal_dict):
debug_values_elems = valobj.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
x = debug_values_elems.GetChildAtIndex(0).GetValue()
y = debug_values_elems.GetChildAtIndex(1).GetValue()
z = debug_values_elems.GetChildAtIndex(2).GetValue()
w = debug_values_elems.GetChildAtIndex(3).GetValue()
if w is not None:
return f'{{{x}, {y}, {z}, {w}}}'
if z is not None:
return f'{{{x}, {y}, {z}}}'
if y is not None:
return f'{{{x}, {y}}}'
return None
class math_matrix_SyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
if valobj.GetChildMemberWithName('w') is not None:
self.len = 4
elif valobj.GetChildMemberWithName('z') is not None:
self.len = 3
elif valobj.GetChildMemberWithName('y') is not None:
self.len = 2
def num_children(self):
return self.len
def get_child_at_index(self, index):
matrix_type_name = self.valobj.GetTypeName()
if "float4" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::float4")
elif "float3" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::float3")
elif "float2" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::float2")
elif "double4" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::double4")
elif "double3" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::double3")
elif "double2" in matrix_type_name:
vec_type = self.valobj.GetTarget().FindFirstType("blender::double2")
if index == 0:
return self.valobj.GetChildMemberWithName('x').Cast(vec_type)
if index == 1:
return self.valobj.GetChildMemberWithName('y').Cast(vec_type)
if index == 2:
return self.valobj.GetChildMemberWithName('z').Cast(vec_type)
if index == 3:
return self.valobj.GetChildMemberWithName('w').Cast(vec_type)
return None
class bli_vector_SyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
self.begin = self.valobj.GetChildMemberWithName("begin_")
self.end = self.valobj.GetChildMemberWithName("end_")
self.capacity_end = self.valobj.GetChildMemberWithName("capacity_end_")
self.data_type = self.begin.GetType().GetPointeeType()
self.data_size = self.data_type.GetByteSize()
def num_children(self):
try:
start_val = self.begin.GetValueAsUnsigned(0)
end_val = self.end.GetValueAsUnsigned(0)
end_capacity_val = self.capacity_end.GetValueAsUnsigned(0)
# Make sure nothing is NULL.
if start_val == 0 or end_val == 0 or end_capacity_val == 0:
return 0
# Make sure start is less than finish.
if start_val >= end_val:
return 0
# Make sure finish is less than or equal to end of storage.
if end_val > end_capacity_val:
return 0
size_in_bytes = (end_val - start_val)
if (size_in_bytes % self.data_size) != 0:
return 0
return (size_in_bytes // self.data_size)
except:
return 0
def get_child_at_index(self, index):
begin = self.valobj.GetChildMemberWithName("begin_")
data_type = begin.GetType().GetPointeeType()
data_size = data_type.GetByteSize()
offset = index * data_size
return begin.CreateChildAtOffset(f"[{index}]", offset, data_type)