| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # |
| # Copyright (C) 2020 Apple Inc. 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. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. |
| |
| |
| # This script generates the source files for WebGL GPU process IPC. |
| # |
| # python3 -m black -l 150 Tools/Scripts/generate-gpup-webgl |
| # python3 -m mypy Tools/Scripts/generate-gpup-webgl |
| # |
| import argparse |
| import enum |
| import pathlib |
| import re |
| import sys |
| import collections |
| |
| from typing import List, Dict, Iterable, Callable, Tuple, Set, Optional, Generator, Iterator, Counter |
| |
| root_dir = (pathlib.Path(__file__).parent / ".." / "..").resolve() |
| |
| functions_input_fns = [root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxy.h"] |
| types_input_fn = root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxy.h" |
| |
| |
| template_preamble = """/* Copyright (C) 2020 Apple Inc. 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. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. |
| */ |
| |
| // This file is generated by generate-gpup-webgl. Do not edit. |
| """ |
| context_functions_header_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGLFunctionsGenerated.h" |
| context_functions_header_template = ( |
| template_preamble |
| + """// This file should be included in the private section of the |
| // RemoteGraphicsContextGL implementations. |
| #pragma once |
| {} |
| |
| """ |
| ) |
| context_functions_impl_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGLFunctionsGenerated.cpp" |
| context_functions_impl_template = ( |
| template_preamble |
| + """ |
| #include "config.h" |
| #include "RemoteGraphicsContextGL.h" |
| |
| #include "Logging.h" |
| #include <wtf/StdLibExtras.h> |
| |
| #if ENABLE(GPU_PROCESS) && ENABLE(WEBGL) |
| |
| #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_connection); |
| |
| namespace WebKit {{ |
| using namespace WebCore; |
| |
| {} |
| |
| }} |
| |
| #undef MESSAGE_CHECK |
| #endif |
| """ |
| ) |
| |
| context_messages_fn = root_dir / "Source" / "WebKit" / "GPUProcess" / "graphics" / "RemoteGraphicsContextGL.messages.in" |
| context_messages_template = ( |
| template_preamble |
| + """#if ENABLE(GPU_PROCESS) && ENABLE(WEBGL) |
| |
| [ |
| DispatchedFrom=WebContent, |
| DispatchedTo=GPU, |
| EnabledBy=WebGLEnabled && UseGPUProcessForWebGLEnabled |
| ] |
| messages -> RemoteGraphicsContextGL Stream {{ |
| void Reshape(int32_t width, int32_t height) |
| #if PLATFORM(COCOA) |
| void PrepareForDisplay(IPC::Semaphore finishedFence) -> (MachSendRight displayBuffer) Synchronous NotStreamEncodable NotStreamEncodableReply |
| #endif |
| #if USE(GRAPHICS_LAYER_WC) |
| void PrepareForDisplay() -> (std::optional<WebKit::WCContentBufferIdentifier> contentBuffer) Synchronous |
| #endif |
| #if USE(GBM) |
| void PrepareForDisplay() -> (uint64_t bufferID, struct std::optional<WebCore::DMABufBufferAttributes> dmabufAttributes, UnixFileDescriptor fenceFD) Synchronous NotStreamEncodableReply |
| #endif |
| #if !PLATFORM(COCOA) && !USE(GRAPHICS_LAYER_WC) && !USE(GBM) |
| void PrepareForDisplay() -> () Synchronous |
| #endif |
| void EnsureExtensionEnabled(WebCore::GCGLExtension extension) |
| void GetErrors() -> (GCGLErrorCodeSet returnValue) Synchronous |
| void copyNativeImageYFlipped(enum:bool WebCore::GraphicsContextGLSurfaceBuffer buffer, WebCore::RenderingResourceIdentifier nativeImageIdentifier) |
| #if ENABLE(MEDIA_STREAM) || ENABLE(WEB_CODECS) |
| void SurfaceBufferToVideoFrame(enum:bool WebCore::GraphicsContextGLSurfaceBuffer buffer) -> (struct std::optional<WebKit::RemoteVideoFrameProxyProperties> properties) Synchronous |
| #endif |
| #if ENABLE(VIDEO) && PLATFORM(COCOA) |
| void CopyTextureFromVideoFrame(struct WebKit::SharedVideoFrame frame, PlatformGLObject texture, uint32_t target, int32_t level, uint32_t internalFormat, uint32_t format, uint32_t type, bool premultiplyAlpha, bool flipY) -> (bool success) Synchronous NotStreamEncodable |
| void SetSharedVideoFrameSemaphore(IPC::Semaphore semaphore) NotStreamEncodable |
| void SetSharedVideoFrameMemory(WebCore::SharedMemory::Handle storageHandle) NotStreamEncodable |
| #endif |
| void SimulateEventForTesting(enum:uint8_t WebCore::GraphicsContextGLSimulatedEventForTesting event) |
| void GetBufferSubDataInline(uint32_t target, uint64_t offset, uint64_t dataSize) -> (std::span<const uint8_t> data) Synchronous |
| void GetBufferSubDataSharedMemory(uint32_t target, uint64_t offset, uint64_t dataSize, WebCore::SharedMemory::Handle handle) -> (bool valid) Synchronous NotStreamEncodable |
| void ReadPixelsInline(WebCore::IntRect rect, uint32_t format, uint32_t type, bool packReverseRowOrder) -> (std::optional<WebCore::IntSize> readArea, std::span<const uint8_t> data) Synchronous |
| void ReadPixelsSharedMemory(WebCore::IntRect rect, uint32_t format, uint32_t type, bool packReverseRowOrder, WebCore::SharedMemory::Handle handle) -> (std::optional<WebCore::IntSize> readArea) Synchronous NotStreamEncodable |
| void MultiDrawArraysANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t> firstsAndCounts) |
| void MultiDrawArraysInstancedANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t> firstsCountsAandInstanceCounts) |
| void MultiDrawElementsANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t> countsAndOffsets, uint32_t type) |
| void MultiDrawElementsInstancedANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t> countsOffsetsAndInstanceCounts, uint32_t type) |
| void MultiDrawArraysInstancedBaseInstanceANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t, uint32_t> firstsCountsInstanceCountsAndBaseInstances) |
| void MultiDrawElementsInstancedBaseVertexBaseInstanceANGLE(uint32_t mode, IPC::ArrayReferenceTuple<int32_t, int32_t, int32_t, int32_t, uint32_t> countsOffsetsInstanceCountsBaseVerticesAndBaseInstances, uint32_t type) |
| void DrawBuffers(std::span<const uint32_t> bufs) |
| void DrawBuffersEXT(std::span<const uint32_t> bufs) |
| void InvalidateFramebuffer(uint32_t target, std::span<const uint32_t> attachments) |
| void InvalidateSubFramebuffer(uint32_t target, std::span<const uint32_t> attachments, int32_t x, int32_t y, int32_t width, int32_t height) |
| #if ENABLE(WEBXR) |
| [EnabledBy=WebXREnabled] void FramebufferDiscard(uint32_t target, std::span<const uint32_t> attachments) |
| #endif |
| void SetDrawingBufferColorSpace(WebCore::DestinationColorSpace colorSpace) |
| {} |
| }} |
| |
| #endif |
| """ |
| ) |
| |
| context_proxy_functions_fn = root_dir / "Source" / "WebKit" / "WebProcess" / "GPU" / "graphics" / "RemoteGraphicsContextGLProxyFunctionsGenerated.cpp" |
| context_proxy_functions_template = ( |
| template_preamble |
| + """ |
| #include "config.h" |
| #include "RemoteGraphicsContextGLProxy.h" |
| |
| #include <wtf/StdLibExtras.h> |
| |
| #if ENABLE(GPU_PROCESS) && ENABLE(WEBGL) |
| |
| namespace WebKit {{ |
| {} |
| |
| }} |
| |
| #endif |
| |
| """ |
| ) |
| |
| |
| def write_file(fn, new_contents): |
| try: |
| with open(fn) as f: |
| if f.read() == new_contents: |
| return |
| except: |
| pass |
| with open(fn, "w") as f: |
| f.write(new_contents) |
| |
| |
| class cpp_type(object): |
| type_name: str |
| |
| def __init__(self, type_name: str): |
| self.type_name = type_name |
| |
| def __str__(self): |
| return self.type_name |
| |
| def __hash__(self): |
| return hash(self.type_name) |
| |
| def __repr__(self): |
| return self.type_name |
| |
| def __eq__(self, other): |
| return self.type_name == other.type_name |
| |
| def is_void(self) -> bool: |
| return self.type_name in ["void", "GCGLvoid", "const void", "const GCGLvoid"] |
| |
| def is_const(self) -> bool: |
| return self.type_name.startswith("const ") |
| |
| def is_container(self) -> bool: |
| return False |
| |
| def is_output_buffer_type(self) -> bool: |
| return False |
| |
| def is_span(self) -> bool: |
| return False |
| |
| def is_dynamic_span(self) -> bool: |
| return False |
| |
| def is_pointer(self) -> bool: |
| return False |
| |
| def is_const_pointer(self) -> bool: |
| return False |
| |
| def is_reference(self) -> bool: |
| return False |
| |
| def is_rvalue_reference(self): |
| return False |
| |
| def is_const_reference(self) -> bool: |
| return False |
| |
| def get_value_type(self) -> "cpp_type": |
| return self |
| |
| def get_decay_type(self) -> "cpp_type": |
| if self.is_const(): |
| return get_cpp_type(self.type_name[6:]) |
| return self |
| |
| def get_rvalue_type(self) -> "cpp_type": |
| return get_cpp_type(self.type_name + "&&") |
| |
| def get_pointer_type(self) -> "cpp_type": |
| return get_cpp_type(self.type_name + "*") |
| |
| |
| class cpp_type_container(cpp_type): |
| container_name: str |
| contained_type: cpp_type |
| arity: Optional[int] |
| |
| def __init__(self, type_name: str, container_name: str, contained_type: cpp_type, arity: Optional[int] = None): |
| cpp_type.__init__(self, type_name) |
| self.container_name = container_name |
| self.contained_type = contained_type |
| self.arity = arity |
| |
| def is_container(self) -> bool: |
| return True |
| |
| def is_span(self) -> bool: |
| return self.container_name == "std::span" |
| |
| def is_dynamic_span(self) -> bool: |
| return (self.container_name == "std::span" and self.arity is None) or self.container_name == "GCGLSpanTuple" |
| |
| def is_array(self) -> bool: |
| return self.container_name == "std::array" |
| |
| def get_container_name(self): |
| return self.container_name |
| |
| def get_arity(self) -> Optional[int]: |
| return self.arity |
| |
| def get_contained_type(self) -> cpp_type: |
| return self.contained_type |
| |
| def is_output_buffer_type(self) -> bool: |
| return self.contained_type.is_const() |
| |
| |
| def create_cpp_type_container(type_name: str) -> Optional[cpp_type_container]: |
| # The logic to determine container is to just assume all templates are containers. |
| m = re.match(r"([\w:]+)<(.+)>$", type_name) |
| if not m: |
| return None |
| container_name = m[1] |
| # All templates are containers except these below. |
| if container_name in ["RefPtr", "Ref", "RetainPtr", "std::optional"]: |
| return None |
| templates = m[2] |
| arity = None |
| m = re.match(r"([^,]+),\s*(\d+)", templates) |
| if m: |
| templates = m[1] |
| arity = int(m[2]) |
| return cpp_type_container(type_name, container_name, get_cpp_type(templates), arity) |
| |
| |
| class cpp_type_function(cpp_type): |
| def __init__(self, type_name: str, return_value_type: cpp_type, argument_types: List[cpp_type]): |
| cpp_type.__init__(self, type_name) |
| self.return_value_type = return_value_type |
| self.argument_types = argument_types |
| |
| |
| def cpp_split_args_specs(args_spec: str) -> Iterator[str]: |
| # https://stackoverflow.com/questions/33527245/python-split-by-comma-skipping-the-content-inside-parentheses |
| comma = r",(?!(?:[^<]*\<[^>]*\>)*[^<>]*\>)" |
| return filter(None, [a.strip() for a in re.split(comma, args_spec.strip())]) |
| |
| |
| def create_cpp_type_function(type_name: str) -> Optional[cpp_type_function]: |
| m = re.match(r"(.*)\((.*)\)", type_name) |
| if not m: |
| return None |
| return_value_type = get_cpp_type(m[1]) |
| args_types = [get_cpp_type(a) for a in cpp_split_args_specs(m[2])] |
| return cpp_type_function(type_name, return_value_type, args_types) |
| |
| |
| # Pointer or refererence |
| class cpp_type_indirect(cpp_type): |
| category: str |
| value_type: cpp_type |
| |
| def __init__(self, type_name: str, category: str, value_type: cpp_type): |
| cpp_type.__init__(self, type_name) |
| self.category = category |
| self.value_type = value_type |
| |
| def is_const_pointer(self): |
| return self.category == "*" and self.is_const() |
| |
| def is_pointer(self): |
| return self.category == "*" and not self.is_const() |
| |
| def is_const_reference(self): |
| return self.category == "&" and self.is_const() |
| |
| def is_reference(self): |
| return self.category == "&" and not self.is_const() |
| |
| def is_rvalue_reference(self): |
| return self.category == "&&" |
| |
| def get_value_type(self): |
| return self.value_type |
| |
| |
| def create_cpp_type_indirect(type_name: str) -> Optional[cpp_type_indirect]: |
| m = re.match(r"const (.+)&&$", type_name) |
| if not m: |
| m = re.match(r"(.+)&&$", type_name) |
| if m: |
| return cpp_type_indirect(type_name, "&&", get_cpp_type(m[1])) |
| m = re.match(r"const (.+)&$", type_name) |
| if not m: |
| m = re.match(r"(.+)&$", type_name) |
| if m: |
| return cpp_type_indirect(type_name, "&", get_cpp_type(m[1])) |
| m = re.match(r"const (.+)\*$", type_name) |
| if not m: |
| m = re.match(r"(.+)\*$", type_name) |
| if m: |
| return cpp_type_indirect(type_name, "*", get_cpp_type(m[1])) |
| return None |
| |
| |
| class cpp_expr(object): |
| type: cpp_type |
| expr: str |
| |
| def __init__(self, type: cpp_type, expr: str): |
| self.type = type |
| self.expr = expr |
| |
| def __str__(self): |
| return self.expr |
| |
| |
| CppExprConverter = Callable[[cpp_expr, cpp_type], cpp_expr] |
| |
| |
| def cpp_reinterpret_cast_from_pointer_through(cast_through_type: cpp_type) -> Callable[[cpp_expr, cpp_type], cpp_expr]: |
| def cpp_reinterpret_cast_from_pointer(expr: cpp_expr, type: cpp_type) -> cpp_expr: |
| return cpp_expr(type, f"static_cast<{type.type_name}>(reinterpret_cast<{str(cast_through_type)}>({str(expr)}))") |
| |
| return cpp_reinterpret_cast_from_pointer |
| |
| |
| def cpp_reinterpret_cast_to_pointer_through(cast_through_type: cpp_type) -> Callable[[cpp_expr, cpp_type], cpp_expr]: |
| def cpp_reinterpret_cast_to_pointer(expr: cpp_expr, type: cpp_type) -> cpp_expr: |
| return cpp_expr(type, f"reinterpret_cast<{type.type_name}>(static_cast<{str(cast_through_type)}>({str(expr)}))") |
| |
| return cpp_reinterpret_cast_to_pointer |
| |
| |
| def cpp_static_cast(expr: cpp_expr, type: cpp_type) -> cpp_expr: |
| return cpp_expr(type, f"static_cast<{type.type_name}>({str(expr)})") |
| |
| |
| def cpp_implicit_cast(expr: cpp_expr, type: cpp_type) -> cpp_expr: |
| return cpp_expr(type, str(expr)) |
| |
| |
| def cpp_array_reinterpret_cast_conversion(expr: cpp_expr, type: cpp_type_container) -> cpp_expr: |
| target_value_type = type.get_contained_type().get_decay_type() |
| target_arity = f", {type.arity}" if type.arity else "" |
| source_value_type = expr.type.get_contained_type().get_decay_type() |
| source_arity = f", {expr.type.arity}" if expr.type.arity else "" |
| if expr.type.is_array(): |
| return cpp_expr( |
| type, f"spanReinterpretCast<const {target_value_type}{target_arity}>(std::span<const {source_value_type}{source_arity}>({str(expr)}))" |
| ) |
| else: |
| return cpp_expr(type, f"spanReinterpretCast<const {target_value_type}{target_arity}>({str(expr)}.span())") |
| |
| |
| def cpp_move_expr(expr: cpp_expr) -> cpp_expr: |
| return cpp_expr(expr.type.get_rvalue_type(), f"WTF::move({str(expr)})") |
| |
| |
| cpp_types: Dict[str, cpp_type] = {} |
| |
| cpp_type_constructors: List[Callable[[str], Optional[cpp_type]]] = [create_cpp_type_function, create_cpp_type_container, create_cpp_type_indirect] |
| |
| |
| def get_cpp_type(type_name: str): |
| r = cpp_types.get(type_name, None) |
| if r: |
| return r |
| for type_constr in cpp_type_constructors: |
| r = type_constr(type_name) |
| if r: |
| break |
| if not r: |
| r = cpp_type(type_name) |
| cpp_types[type_name] = r |
| return r |
| |
| |
| class cpp_arg(object): |
| name: str |
| type: cpp_type |
| |
| def __init__(self, type: cpp_type, name: str): |
| self.name = name |
| self.type = type |
| |
| def get_declaration(self): |
| if self.name == "completionHandler": |
| return "{}".format(self.type) |
| return str(self) |
| |
| def __str__(self): |
| return "{} {}".format(self.type, self.name) |
| |
| |
| class cpp_decl(object): |
| type: cpp_type |
| name: str |
| |
| def __init__(self, type: cpp_type, name: str): |
| self.type = type |
| self.name = name |
| |
| def __str__(self): |
| return f"{str(self.type)} {self.name}" |
| |
| |
| class cpp_arg_list(object): |
| args: List[cpp_arg] |
| |
| def __init__(self, args: List[cpp_arg]): |
| self.args = args |
| |
| def names(self): |
| return ", ".join(a.name for a in self.args) |
| |
| def exprs(self): |
| return [cpp_expr(a.type, a.name) for a in self.args] |
| |
| def decls(self): |
| return [cpp_decl(a.type, a.name) for a in self.args] |
| |
| def types(self): |
| return [a.type for a in self.args] |
| |
| def get_declaration(self): |
| return ", ".join(a.get_declaration() for a in self.args) |
| |
| def __str__(self): |
| return ", ".join(str(a) for a in self.args) |
| |
| |
| class cpp_func(object): |
| name: str |
| args: cpp_arg_list |
| return_type: cpp_type |
| enabled_by: str |
| message_check: str |
| cond: str |
| overload_suffix: str |
| |
| def __init__(self, name: str, return_type: cpp_type, args: cpp_arg_list, enabled_by: str, message_check: str, cond: str): |
| self.name = name |
| self.return_type = return_type |
| self.args = args |
| self.enabled_by = enabled_by |
| self.message_check = message_check |
| self.cond = cond |
| self.overload_suffix = "" |
| |
| def __str__(self): |
| return f"{self.return_type} {self.name}({str(self.args)})" |
| |
| def get_args_categories(self) -> Tuple[List[cpp_arg], List[cpp_arg]]: |
| in_args = [] |
| out_args = [] |
| for a in self.args.args: |
| # fmt: off |
| if a.type.is_pointer() or \ |
| a.type.is_reference(): |
| out_args += [a] |
| elif isinstance(a.type, cpp_type_container) and (((a.type.is_span() or a.type.is_dynamic_span()) and not a.type.get_contained_type().is_const())): |
| out_args += [a] |
| else: |
| in_args += [a] |
| # fmt: on |
| return in_args, out_args |
| |
| def is_implemented_type(self, type: cpp_type): |
| if type.is_const_pointer(): |
| return False |
| return True |
| |
| def is_implemented(self): |
| # " in a.type.type_name for a in self.args.args): |
| # return False |
| # if "GCGLsync" in self.return_type.type_name: |
| # return False |
| if any(a.name == "bufSize" for a in self.args.args): |
| return False |
| if any(a.type.is_pointer() and a.type.get_value_type().is_void() for a in self.args.args): |
| return False |
| if any(not self.is_implemented_type(a.type) for a in self.args.args): |
| return False |
| if self.return_type.is_pointer(): |
| return False |
| if not self.is_implemented_type(self.return_type): |
| return False |
| return True |
| |
| |
| webkit_ipc_types: Dict[cpp_type, cpp_type] = {} |
| |
| webkit_ipc_types_converters: Dict[Tuple[cpp_type, cpp_type], CppExprConverter] = {} |
| |
| |
| def webkit_ipc_convert_expr(expr: cpp_expr, type: cpp_type) -> cpp_expr: |
| """Converts `expr` of type of `self` to `type`""" |
| convert = webkit_ipc_types_converters.get((expr.type, type), None) |
| if convert: |
| return convert(expr, type) |
| if expr.type == type: |
| return expr |
| elif expr.type.is_rvalue_reference() and expr.type.get_value_type() == type: |
| return webkit_ipc_move_expr(expr) |
| elif type.is_rvalue_reference() and type.get_value_type() == expr.type: |
| return webkit_ipc_move_expr(expr) |
| return cpp_implicit_cast(expr, type) |
| |
| |
| def webkit_ipc_get_span_transfer_type(type: cpp_type_container) -> cpp_type: |
| element_type = type.get_contained_type().get_decay_type() |
| arity = type.get_arity() |
| webkit_ipc_element_type = webkit_ipc_types[element_type] if not element_type.is_void() else get_cpp_type("uint8_t") |
| if arity is not None: |
| return get_cpp_type(f"std::span<const {str(webkit_ipc_element_type)}, {arity}>") |
| return get_cpp_type(f"std::span<const {str(webkit_ipc_element_type)}>") |
| |
| |
| def webkit_ipc_get_span_store_type(type: cpp_type_container) -> cpp_type: |
| element_type = type.get_contained_type().get_decay_type() |
| if element_type.is_void(): |
| element_type = get_cpp_type("GCGLchar") |
| if type.is_dynamic_span(): |
| inline_capacity = 16 if "float" in element_type.type_name else 4 |
| return get_cpp_type(f"Vector<{str(element_type)}, {str(inline_capacity)}>") |
| return get_cpp_type(f"std::array<{str(element_type)}, {str(type.get_arity())}>") |
| |
| |
| # See messages.py function_parameter_type |
| webkit_ipc_builtin_types = set( |
| ["uint8_t", "uint16_t", "uint32_t", "uint64_t", "int8_t", "int16_t", "int32_t", "int64_t", "bool", "float", "double" "bool"] |
| ) |
| |
| |
| def webkit_ipc_get_message_forwarder_type(type: cpp_type) -> cpp_type: |
| if type.type_name in webkit_ipc_builtin_types: |
| return type |
| return type.get_rvalue_type() |
| |
| |
| def webkit_ipc_move_expr(expr: cpp_expr) -> cpp_expr: |
| if expr.type.type_name in webkit_ipc_builtin_types: |
| return expr |
| return cpp_move_expr(expr) |
| |
| |
| def webkit_ipc_msg_name(func: cpp_func): |
| return func.name[0].capitalize() + func.name[1:] + func.overload_suffix |
| |
| |
| def to_variable_name(name: str) -> str: |
| return name[0].lower() + name[1:] |
| |
| |
| def to_member_variable_name(name: str) -> str: |
| return f"m_{to_variable_name(name)}" |
| |
| |
| def is_create_func(func: cpp_func) -> bool: |
| return func.name.startswith("create") |
| |
| |
| def get_create_func_object_name(name: str) -> str: |
| return name[len("create") :] |
| |
| |
| def is_delete_func(func: cpp_func) -> bool: |
| return func.name.startswith("delete") |
| |
| |
| def get_delete_func_object_name(name: str) -> str: |
| return name[len("delete") :] |
| |
| |
| def webkit_ipc_msg_arg_type(cpp_type: cpp_type) -> cpp_type: |
| ipc_type = webkit_ipc_types[cpp_type] |
| # FIXME: the messages.py generator should read the serializers and not need this. |
| if ipc_type == get_cpp_type("WebCore::GraphicsContextGLFlipY"): |
| return get_cpp_type("enum:bool WebCore::GraphicsContextGLFlipY") |
| if ipc_type == get_cpp_type("WebCore::GraphicsContextGLSimulatedEventForTesting"): |
| return get_cpp_type("enum:uint8_t WebCore::GraphicsContextGLSimulatedEventForTesting") |
| return ipc_type |
| |
| |
| # FIXME: these should be removed and IPC should know this. |
| non_stream_types = set({"WebCore::GraphicsContextGL::ExternalImageSource&&", "WebCore::GraphicsContextGL::ExternalSyncSource&&"}) |
| |
| |
| class webkit_ipc_msg(object): |
| cond: str |
| enabled_by: str |
| name: str |
| in_args: cpp_arg_list |
| out_args: cpp_arg_list |
| |
| def __init__(self, func: cpp_func): |
| self.cond = func.cond |
| self.enabled_by = func.enabled_by |
| self.name = webkit_ipc_msg_name(func) |
| in_args, out_args = func.get_args_categories() |
| ipc_in_args = [cpp_arg(webkit_ipc_msg_arg_type(a.type), a.name) for a in in_args] |
| ipc_out_args = [] |
| if is_create_func(func): |
| name = get_create_func_object_name(func.name) |
| ipc_in_args.insert(0, cpp_arg(webkit_ipc_types[func.return_type], to_variable_name(name))) |
| elif not func.return_type.is_void(): |
| ipc_out_args += [cpp_arg(webkit_ipc_types[func.return_type], "returnValue")] |
| for a in out_args: |
| ipc_out_args += [cpp_arg(webkit_ipc_types[a.type], a.name)] |
| if a.type.is_dynamic_span(): |
| ipc_in_args += [cpp_arg(get_cpp_type("uint64_t"), f"{a.name}Size")] |
| self.in_args = cpp_arg_list(ipc_in_args) |
| self.out_args = cpp_arg_list(ipc_out_args) |
| self.tags = [] |
| if any(arg.type.type_name in non_stream_types for arg in in_args): |
| self.tags += ["NotStreamEncodable"] |
| |
| def __str__(self): |
| tags = f" {' '.join(self.tags)}" if self.tags else "" |
| enabled_by = f"[EnabledBy={self.enabled_by}] " if self.enabled_by else "" |
| if len(self.out_args.args): |
| return f"\n {enabled_by}void {self.name}({str(self.in_args)}) -> ({str(self.out_args)}) Synchronous{tags}" |
| return f"\n {enabled_by}void {self.name}({str(self.in_args)}){tags}" |
| |
| |
| class webkit_ipc_cpp_proxy_impl(object): |
| cond: str |
| name: str |
| is_create: bool |
| msg_name: str |
| return_type: cpp_type |
| args: cpp_arg_list |
| |
| pre_call_stmts: List[str] |
| call_stmts: List[str] |
| post_call_stmts: List[str] |
| return_stmts: List[str] |
| in_exprs: List[cpp_expr] |
| out_exprs: List[cpp_expr] |
| |
| def __init__(self, cpp_func: cpp_func): |
| self.cond = cpp_func.cond |
| self.name = cpp_func.name |
| self.is_create = is_create_func(cpp_func) |
| self.msg_name = webkit_ipc_msg_name(cpp_func) |
| self.return_type = cpp_func.return_type |
| self.args = cpp_func.args |
| self.pre_call_stmts = [] |
| self.call_stmts = [] |
| self.post_call_stmts = [] |
| self.return_stmts = [] |
| self.in_exprs = [] |
| self.out_exprs = [] |
| in_args, out_args = cpp_func.get_args_categories() |
| self.process_return_value(cpp_func.return_type) |
| self.process_in_args(in_args) |
| self.process_out_args(out_args) |
| self.process_call() |
| |
| def process_call(self): |
| in_exprs = ", ".join([str(i) for i in self.in_exprs]) |
| out_exprs = ", ".join(str(o) for o in self.out_exprs) |
| is_async = (self.return_type.is_void() or self.is_create) and len(out_exprs) == 0 |
| self.call_stmts += ["if (isContextLost())"] |
| if self.return_type.is_void(): |
| self.call_stmts += [" return;"] |
| else: |
| self.call_stmts += [" return { };"] |
| if self.is_create: |
| self.call_stmts += [f"auto name = createObjectName();"] |
| if is_async: |
| self.call_stmts += [ |
| f"auto sendResult = send(Messages::RemoteGraphicsContextGL::{self.msg_name}({in_exprs}));", |
| "if (sendResult != IPC::Error::NoError) {", |
| ] |
| else: |
| self.call_stmts += [ |
| f"auto sendResult = sendSync(Messages::RemoteGraphicsContextGL::{self.msg_name}({in_exprs}));", |
| "if (!sendResult.succeeded()) {", |
| ] |
| if self.return_type.is_void(): |
| self.call_stmts += [ |
| " markContextLost();", |
| " return;", |
| "}", |
| ] |
| else: |
| self.call_stmts += [ |
| " markContextLost();", |
| " return { };", |
| "}", |
| ] |
| |
| def process_in_args(self, in_args: List[cpp_arg]): |
| if self.is_create: |
| self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(self.return_type, "name"), webkit_ipc_types[self.return_type])] |
| for i in in_args: |
| if i.type.is_const_pointer(): |
| assert False |
| else: |
| self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(i.type, i.name), webkit_ipc_types[i.type])] |
| |
| def process_out_args(self, out_args: List[cpp_arg]): |
| for o in out_args: |
| if o.type.is_pointer(): |
| value_type = o.type.get_value_type() |
| webkit_ipc_value_type = webkit_ipc_types[value_type] |
| v = cpp_arg(webkit_ipc_value_type, o.name + "Reply") |
| e = cpp_expr(v.type, v.name) |
| self.out_exprs += [e] |
| self.post_call_stmts += [ |
| # fmt: off |
| f"if ({o.name})", |
| f" *{o.name} = {webkit_ipc_convert_expr(e, value_type)};" |
| # fmt: on |
| ] |
| elif o.type.is_reference(): |
| value_type = o.type.get_value_type() |
| v = cpp_arg(value_type, o.name + "Reply") |
| e = cpp_expr(v.type, v.name) |
| self.out_exprs += [e] |
| self.post_call_stmts += [ |
| f"{o.name} = WTF::move({v.name});", |
| ] |
| elif o.type.is_span(): |
| webkit_ipc_type = webkit_ipc_types[o.type] |
| assert isinstance(webkit_ipc_type, cpp_type_container) |
| v = cpp_arg(webkit_ipc_type, o.name + "Reply") |
| self.out_exprs += [cpp_expr(v.type, v.name)] |
| if o.type.is_dynamic_span(): |
| self.in_exprs += [cpp_expr(get_cpp_type("size_t"), f"{o.name}.size()")] |
| self.post_call_stmts += [f"memcpySpan({o.name}, {v.name});"] |
| else: |
| self.out_exprs += [cpp_expr(o.type, o.name)] |
| |
| if self.out_exprs: |
| out_exprs = ", ".join(str(o) for o in self.out_exprs) |
| self.post_call_stmts = [ |
| f"auto& [{out_exprs}] = sendResult.reply();", |
| ] + self.post_call_stmts |
| |
| def process_return_value(self, return_type: cpp_type): |
| if return_type.is_void(): |
| return |
| if self.is_create: |
| self.return_stmts = [f"return name;"] |
| return |
| self.return_type = return_type |
| ipc_return_type = webkit_ipc_types[return_type] |
| return_value_expr = cpp_expr(ipc_return_type, "returnValue") |
| self.out_exprs = [return_value_expr] + self.out_exprs |
| self.return_stmts = [f"return {str(webkit_ipc_convert_expr(return_value_expr, return_type))};"] |
| |
| def __str__(self): |
| nolint = " // NOLINT" if "_" in self.name else "" |
| body = "".join(f"\n {b}" for b in self.pre_call_stmts + self.call_stmts + self.post_call_stmts + self.return_stmts) |
| return f"""\n{str(self.return_type)} RemoteGraphicsContextGLProxy::{self.name}({str(self.args)}){nolint} |
| {{{body} |
| }}""" |
| |
| |
| class webkit_ipc_cpp_proxy_placeholder(object): |
| name: str |
| return_type: cpp_type |
| args: cpp_arg_list |
| body: List[str] |
| |
| def __init__(self, cpp_func: cpp_func): |
| self.name = cpp_func.name |
| |
| self.return_type = cpp_func.return_type |
| self.args = cpp_func.args |
| self.body = ["notImplemented();"] |
| if cpp_func.return_type.type_name != "void": |
| self.body += ["return { };"] |
| |
| def __str__(self): |
| nolint = " // NOLINT" if "_" in self.name else "" |
| body = "\n{\n " + "\n ".join(self.body) + "\n}" |
| return f"\n{str(self.return_type)} RemoteGraphicsContextGLProxy::{self.name}({str(self.args)}){nolint}{body}" |
| |
| |
| class context_proxy_cpp_webkit_ipc_generator(object): |
| "RemoteGraphicsContextGLProxy C++ implementation generator." |
| |
| impls: List[webkit_ipc_cpp_proxy_impl] |
| unimpls: List[webkit_ipc_cpp_proxy_placeholder] |
| cond: str |
| |
| def __init__(self, funcs: Iterable[cpp_func], unimplemented: Iterable[cpp_func]): |
| self.impls = [webkit_ipc_cpp_proxy_impl(f) for f in funcs] |
| self.unimpls = [webkit_ipc_cpp_proxy_placeholder(f) for f in unimplemented] |
| self.cond = "" |
| |
| def open_cond(self, impl): |
| if self.cond != impl.cond: |
| close_cond = "#endif\n" if self.cond else "" |
| open_cond = f"\n#if {impl.cond}" if impl.cond else "" |
| self.cond = impl.cond |
| return f"{close_cond}{open_cond}" |
| return "" |
| |
| def close_cond(self): |
| if self.cond: |
| self.cond = "" |
| return "\n#endif" |
| return "" |
| |
| def get_functions(self): |
| return "\n".join(f"{self.open_cond(i)}{i}" for i in self.impls) + self.close_cond() + "\n".join(str(i) for i in self.unimpls) |
| |
| def generate(self): |
| write_file( |
| context_proxy_functions_fn, |
| context_proxy_functions_template.format(self.get_functions()), |
| ) |
| |
| |
| named_object_types = set(["PlatformGLObject", "GCGLExternalImage", "GCGLExternalSync"]) |
| |
| |
| class webkit_ipc_cpp_impl(object): |
| cond: str |
| name: str |
| enabled_by: str |
| args: cpp_arg_list |
| pre_call_stmts: List[str] |
| call_stmts: List[str] |
| post_call_stmts: List[str] |
| in_exprs: List[cpp_expr] |
| out_exprs: List[cpp_expr] |
| return_value_expr: Optional[cpp_expr] |
| |
| def __init__(self, cpp_func: cpp_func): |
| self.cond = cpp_func.cond |
| self.name = cpp_func.name |
| self.message_check = cpp_func.message_check |
| self.is_create = is_create_func(cpp_func) |
| self.is_delete = is_delete_func(cpp_func) |
| self.overload_suffix = cpp_func.overload_suffix |
| self.args = cpp_arg_list([]) |
| self.pre_call_stmts = [] |
| self.call_stmts = [] |
| self.post_call_stmts = [] |
| self.in_exprs = [] |
| self.out_exprs = [] |
| self.return_value_expr = None |
| |
| self.pre_call_stmts += ["assertIsCurrent(workQueue());"] |
| if self.message_check: |
| self.pre_call_stmts += [f"MESSAGE_CHECK({self.message_check});"] |
| self.process_return_value(cpp_func.return_type) |
| in_args, out_args = cpp_func.get_args_categories() |
| self.process_args(cpp_func.args.args, set(in_args), set(out_args)) |
| self.process_call() |
| |
| def process_call(self): |
| in_exprs = ", ".join(str(e) for e in self.in_exprs) |
| is_async = len(self.out_exprs) == 0 |
| |
| call_expr = f"protectedContext()->{self.name}({in_exprs})" |
| if not self.return_value_expr: |
| self.call_stmts += [f"{call_expr};"] |
| else: |
| self.call_stmts += [f"{str(self.return_value_expr)} = {call_expr};"] |
| if not is_async: |
| out_exprs = ", ".join(str(e) for e in self.out_exprs) |
| self.post_call_stmts += [f"completionHandler({out_exprs});"] |
| |
| def process_args(self, args: List[cpp_arg], in_args: Set[cpp_arg], out_args: Set[cpp_arg]): |
| for a in args: |
| if a.type.is_const_pointer(): |
| assert False |
| if a in in_args: |
| self.process_in_arg(a) |
| else: |
| self.process_out_arg(a) |
| if self.out_exprs: |
| out_arg_decls = ", ".join(f"{str(e.type)}" for e in self.out_exprs) |
| self.args.args += [cpp_arg(get_cpp_type(f"CompletionHandler<void({out_arg_decls})>&&"), "completionHandler")] |
| |
| def process_in_arg(self, a: cpp_arg): |
| self.args.args += [cpp_arg(webkit_ipc_get_message_forwarder_type(webkit_ipc_types[a.type]), a.name)] |
| self.in_exprs += [webkit_ipc_convert_expr(cpp_expr(webkit_ipc_types[a.type], a.name), a.type)] |
| if a.type.type_name in named_object_types: |
| if self.is_create: |
| self.pre_call_stmts += [f"MESSAGE_CHECK({a.name});"] |
| if self.is_delete: |
| self.pre_call_stmts += [ |
| f"MESSAGE_CHECK(m_objectNames.isValidKey({a.name}));", |
| f"if (!{a.name}) [[unlikely]]", |
| f" return;", |
| f"{a.name} = m_objectNames.take({a.name});", |
| ] |
| else: |
| self.pre_call_stmts += [ |
| f"MESSAGE_CHECK(m_objectNames.isValidKey({a.name}));", |
| f"if ({a.name})", |
| f" {a.name} = m_objectNames.get({a.name});", |
| ] |
| |
| def process_out_arg(self, a: cpp_arg): |
| if a.type.is_pointer(): |
| value_arg = cpp_arg(a.type.get_value_type(), a.name) |
| self.pre_call_stmts += [f"{str(value_arg.type)} {str(value_arg.name)} = {{ }};"] |
| self.in_exprs += [cpp_expr(a.type, f"&{value_arg.name}")] |
| e = cpp_expr(value_arg.type, value_arg.name) |
| webkit_ipc_value_type = webkit_ipc_types[e.type] |
| self.out_exprs += [webkit_ipc_convert_expr(e, webkit_ipc_value_type)] |
| elif a.type.is_dynamic_span(): |
| assert isinstance(a.type, cpp_type_container) |
| size_arg = cpp_arg(get_cpp_type("uint64_t"), f"{a.name}Size") |
| self.args.args += [size_arg] |
| store_arg = cpp_arg(webkit_ipc_get_span_store_type(a.type), a.name) |
| inline_capacity = store_arg.type.arity |
| contained_type = a.type.contained_type.type_name |
| self.pre_call_stmts += [f"if (!WTF::isValidCapacityForVector<{contained_type}>({a.name}Size))"] |
| self.pre_call_stmts += [f" {a.name}Size = {inline_capacity};"] |
| self.pre_call_stmts += [f"{str(store_arg.type)} {str(store_arg.name)}({a.name}Size, 0);"] |
| self.in_exprs += [cpp_expr(store_arg.type, f"{store_arg.name}")] |
| webkit_ipc_type = webkit_ipc_types[a.type] |
| self.out_exprs += [webkit_ipc_convert_expr(cpp_expr(store_arg.type, store_arg.name), webkit_ipc_type)] |
| elif a.type.is_span(): |
| assert isinstance(a.type, cpp_type_container) |
| store_arg = cpp_arg(webkit_ipc_get_span_store_type(a.type), a.name) |
| self.pre_call_stmts += [f"{str(store_arg.type)} {str(store_arg.name)} {{ }};"] |
| self.in_exprs += [cpp_expr(store_arg.type, store_arg.name)] |
| webkit_ipc_type = webkit_ipc_types[a.type] |
| self.out_exprs += [webkit_ipc_convert_expr(cpp_expr(store_arg.type, store_arg.name), webkit_ipc_type)] |
| else: |
| assert a.type.is_reference() |
| webkit_ipc_type = webkit_ipc_types[a.type] |
| value_arg = cpp_arg(a.type.get_value_type(), a.name) |
| self.pre_call_stmts += [f"{self.ns(value_arg.type)} {str(value_arg.name)} {{ }};"] |
| e = cpp_expr(value_arg.type, value_arg.name) |
| self.in_exprs += [e] |
| self.out_exprs += [webkit_ipc_move_expr(webkit_ipc_convert_expr(e, webkit_ipc_type))] |
| |
| def process_return_value(self, return_type: cpp_type): |
| if self.is_create: |
| ipc_return_type = webkit_ipc_types[return_type] |
| self.args.args += [cpp_arg(webkit_ipc_get_message_forwarder_type(ipc_return_type), "name")] |
| return_value_expr = cpp_expr(return_type, f"auto result") |
| self.return_value_expr = return_value_expr |
| self.pre_call_stmts += [f"MESSAGE_CHECK(m_objectNames.isValidKey(name));"] |
| self.post_call_stmts += [f"if (result)", f" m_objectNames.add(name, result);"] |
| return |
| if return_type.is_void(): |
| return |
| ipc_return_type = webkit_ipc_types[return_type] |
| return_value_expr = cpp_expr(return_type, "returnValue") |
| self.pre_call_stmts += [f"{return_value_expr.type} {return_value_expr.expr} = {{ }};"] |
| self.out_exprs += [webkit_ipc_move_expr(webkit_ipc_convert_expr(return_value_expr, ipc_return_type))] |
| self.return_value_expr = return_value_expr |
| |
| def get_declaration(self): |
| nolint = " // NOLINT" if "_" in self.name else "" |
| return f""" void {self.name}{self.overload_suffix}({self.args.get_declaration()});{nolint}""" |
| |
| def get_definition(self): |
| nolint = " // NOLINT" if "_" in self.name else "" |
| body = "".join(f"\n {b}" for b in self.pre_call_stmts + self.call_stmts + self.post_call_stmts) |
| return f"""void RemoteGraphicsContextGL::{self.name}{self.overload_suffix}({str(self.args)}){nolint} |
| {{{body} |
| }} |
| """ |
| |
| def ns(self, type: cpp_type): |
| # TODO: namespace info is not stored in names. |
| if type.type_name == "ActiveInfo": |
| return "WebCore::GraphicsContextGL::" + str(type) |
| return str(type) |
| |
| |
| def webkit_ipc_resolve_overload_suffix(funcs: Iterable[cpp_func]): |
| counts = collections.Counter(f.name for f in funcs) |
| suffixes: Counter[str] = collections.Counter() |
| for f in funcs: |
| if counts[f.name] > 1: |
| f.overload_suffix = str(suffixes[f.name]) |
| suffixes.update([f.name]) |
| |
| |
| class context_cpp_webkit_ipc_generator(object): |
| "RemoteGraphicsContextGL C++ implementation generator." |
| |
| impls: List[webkit_ipc_cpp_impl] |
| cond: str |
| |
| def __init__(self, funcs: Iterable[cpp_func]): |
| self.impls = [webkit_ipc_cpp_impl(f) for f in funcs] |
| self.cond = "" |
| |
| def open_cond(self, impl): |
| if self.cond != impl.cond: |
| close_cond = "#endif\n" if self.cond else "" |
| open_cond = f"#if {impl.cond}\n" if impl.cond else "" |
| self.cond = impl.cond |
| return f"{close_cond}{open_cond}" |
| return "" |
| |
| def close_cond(self): |
| if self.cond: |
| self.cond = "" |
| return "\n#endif" |
| return "" |
| |
| def get_declarations(self): |
| return "\n".join(f"{self.open_cond(i)}{i.get_declaration()}" for i in self.impls) + self.close_cond() |
| |
| def get_definitions(self): |
| return "\n".join(f"{self.open_cond(i)}{i.get_definition()}" for i in self.impls) + self.close_cond() |
| |
| def generate(self): |
| write_file( |
| context_functions_header_fn, |
| context_functions_header_template.format(self.get_declarations()), |
| ) |
| |
| write_file( |
| context_functions_impl_fn, |
| context_functions_impl_template.format(self.get_definitions()), |
| ) |
| |
| |
| class context_msg_webkit_ipc_generator(object): |
| "RemoteGraphicsContextGL WebKit IPC message definition generator." |
| |
| msgs: List[webkit_ipc_msg] |
| cond: str |
| |
| def __init__(self, funcs: Iterable[cpp_func]): |
| self.msgs = [webkit_ipc_msg(f) for f in funcs] |
| self.cond = "" |
| |
| def open_cond(self, msg): |
| if self.cond != msg.cond: |
| close_cond = "\n#endif" if self.cond else "" |
| open_cond = f"\n#if {msg.cond}" if msg.cond else "" |
| self.cond = msg.cond |
| return f"{close_cond}{open_cond}" |
| return "" |
| |
| def close_cond(self): |
| if self.cond: |
| self.cond = "" |
| return "\n#endif" |
| return "" |
| |
| def get_messages(self): |
| return "".join(f"{self.open_cond(m)}{m}" for m in self.msgs) + self.close_cond() |
| |
| def generate(self): |
| write_file(context_messages_fn, context_messages_template.format(self.get_messages())) |
| |
| |
| def create_cpp_arg(arg_spec: str, arg_index: int): |
| r = arg_spec.rsplit(" ", 1) |
| name = "" |
| type = None |
| if len(r) > 1 and r[0] != "const": |
| name = r[1].strip() |
| type = get_cpp_type(r[0]) |
| else: |
| name = "arg{}".format(arg_index) |
| type = get_cpp_type(arg_spec) |
| return cpp_arg(type, name) |
| |
| |
| def create_cpp_arg_list(args_specs: Iterable[str]): |
| return cpp_arg_list([create_cpp_arg(arg_spec=e, arg_index=i) for i, e in enumerate(args_specs)]) |
| |
| |
| def create_cpp_func(name: str, return_spec: str, args_specs: List[str], enabled_by: str, message_check: str, cond: str): |
| return cpp_func( |
| name=name, |
| return_type=get_cpp_type(return_spec), |
| args=create_cpp_arg_list(args_specs), |
| enabled_by=enabled_by, |
| message_check=message_check, |
| cond=cond, |
| ) |
| |
| |
| def read_lines_until(lines: Iterable[str], match: str) -> Generator[str, None, None]: |
| for line in lines: |
| if re.match(match, line.strip()): |
| break |
| yield line |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser("usage: %prog [options]") |
| parser.add_argument("--verbose", action="store_true", help="Print some debug info from the generator script") |
| options = parser.parse_args() |
| |
| # Construct the list of functions to remote from web process to GPU process. |
| |
| funcs = [] |
| unimplemented = [] |
| cond = "" |
| message_checks = {} |
| for fn in functions_input_fns: |
| with open(fn) as f: |
| lines = iter(f.readlines()) |
| for _ in read_lines_until(lines, "// Functions with a generated implementation. This list is used by generate-gpup-webgl script."): |
| pass |
| |
| for line in read_lines_until(lines, "// End of list used by generate-gpup-webgl script."): |
| m = re.match(r"\s*#\s*if\s+(.*\S)\s*$", line) |
| if m: |
| # FIXME: Nested conditions are not handled |
| cond = m[1] |
| continue |
| m = re.match(r"\s*#\s*endif", line) |
| if m: |
| cond = "" |
| continue |
| m = re.match(r"\s*(\S+)\s+(\w+)\((.*?)\)\s+(IPC_ENABLED_BY_AND_MESSAGE_CHECK\((\S+?)\s*,\s*(\S+?)\)\s+)?final;", line) |
| if m: |
| func_name = m[2] |
| func = create_cpp_func( |
| name=func_name, return_spec=m[1], args_specs=cpp_split_args_specs(m[3]), enabled_by=m[5], message_check=m[6], cond=cond |
| ) |
| if func.is_implemented(): |
| funcs.append(func) |
| else: |
| unimplemented.append(func) |
| |
| webkit_ipc_resolve_overload_suffix(funcs) |
| # Initialize WebKit IPC generation. Construct type mappings for the used C++ types -> IPC types. |
| # Populate types that are needed but not present in the interfaces. |
| for needed in ["unsigned"]: |
| cpp_type = get_cpp_type(needed) |
| webkit_ipc_types[cpp_type] = cpp_type |
| |
| size_t_cpp_type = get_cpp_type("size_t") |
| webkit_ipc_types[size_t_cpp_type] = get_cpp_type("uint64_t") |
| active_info_types = set(["WebCore::GCGLAttribActiveInfo", "WebCore::GCGLUniformActiveInfo", "WebCore::GCGLTransformFeedbackActiveInfo"]) |
| for builtin_type in webkit_ipc_builtin_types | active_info_types: |
| cpp_type = get_cpp_type(builtin_type) |
| webkit_ipc_types[cpp_type] = cpp_type |
| |
| with open(types_input_fn) as f: |
| lines = iter(f.readlines()) |
| for _ in read_lines_until(lines, "// The GCGL types map to following WebKit IPC types. The list is used by generate-gpup-webgl script."): |
| pass |
| for line in read_lines_until(lines, "// End of list used by generate-gpup-webgl script."): |
| m = re.match(r".*static_assert\(std::is_same_v<(\w+), (\w+)>\);", line) |
| if m: |
| webkit_ipc_types[get_cpp_type(m[1])] = get_cpp_type(m[2]) |
| continue |
| m = re.match(r".*static_assert\(sizeof\((\w+)\) == sizeof\((\w+)\)\);", line) |
| if m: |
| cpp_type = get_cpp_type(m[1]) |
| ipc_type = get_cpp_type(m[2]) |
| webkit_ipc_types[cpp_type] = ipc_type |
| webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_static_cast |
| webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_static_cast |
| continue |
| # FIXME: Here we use <= instead of == due to pointers, such as GCGLsync, GCGLintptr, .... |
| # This ends up failing if there ever is arrays of these types, since arrays are currently |
| # reinterpret-casted. |
| # WebKit IPC requires one sized type, but the size of these pointer-based values will change |
| # based on the platform. |
| m = re.match(r".*static_assert\(sizeof\((\w+)\) <= sizeof\((\w+)\)\);", line) |
| if m: |
| cpp_type = get_cpp_type(m[1]) |
| ipc_type = get_cpp_type(m[2]) |
| webkit_ipc_types[cpp_type] = ipc_type |
| webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_static_cast |
| webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_static_cast |
| continue |
| m = re.match(r".*static_assert\(sizeof\((\w+)\) <= sizeof\((\w+)\) && sizeof\((\w+)\) == sizeof\((\w+)\)\);", line) |
| if m: |
| cpp_type = get_cpp_type(m[1]) |
| ipc_type = get_cpp_type(m[2]) |
| cpp_cast_through_type = get_cpp_type(m[4]) |
| webkit_ipc_types[cpp_type] = ipc_type |
| webkit_ipc_types_converters[(cpp_type, ipc_type)] = cpp_reinterpret_cast_from_pointer_through(cpp_cast_through_type) |
| webkit_ipc_types_converters[(ipc_type, cpp_type)] = cpp_reinterpret_cast_to_pointer_through(cpp_cast_through_type) |
| continue |
| |
| # For all types in the input API, form corresponding IPC types and conversions. |
| # TODO: this is not driven by the typing. |
| all_types = set() |
| for func in funcs: |
| all_types.update(func.args.types() + [func.return_type]) |
| # Sort by len so that template args come before templates. |
| for cpp_type in sorted(all_types, key=lambda x: len(x.type_name)): |
| if cpp_type in webkit_ipc_types: |
| continue |
| |
| if cpp_type.is_dynamic_span() or cpp_type.is_span(): |
| transfer_type = webkit_ipc_get_span_transfer_type(cpp_type) |
| webkit_ipc_types[cpp_type] = transfer_type.get_value_type() |
| store_type = webkit_ipc_get_span_store_type(cpp_type) |
| webkit_ipc_types_converters[(store_type, transfer_type)] = cpp_array_reinterpret_cast_conversion |
| elif cpp_type.is_reference() or cpp_type.is_const_reference() or cpp_type.is_container(): |
| value_type = cpp_type.get_value_type() if not cpp_type.is_container() else cpp_type |
| if value_type.is_container(): |
| contained_type = value_type.get_contained_type() |
| webkit_ipc_contained_type = webkit_ipc_types[contained_type] |
| if webkit_ipc_contained_type == contained_type: |
| webkit_ipc_types[cpp_type] = value_type |
| else: |
| transfer_type = get_cpp_type(f"{value_type.get_container_name()}<{str(webkit_ipc_contained_type)}>") |
| webkit_ipc_types[cpp_type] = transfer_type |
| # TODO: Here might be case where Vector<GCGLint> was used in the interface and Vector<int32_t> is used |
| # in the IPC definition. There is no sensible way to do this at the moment. We do not convert, rather |
| # expect that all the invocations are taken care of the fact that GCGLint is the same type as int32_t. |
| # This will not hold for all types such as GCGLboolean. |
| # webkit_ipc_types_converters[(cpp_type, transfer_type)] = cpp_array_reinterpret_cast_conversion |
| else: |
| webkit_ipc_types[cpp_type] = value_type |
| elif cpp_type.is_rvalue_reference(): |
| webkit_ipc_types[cpp_type] = cpp_type.get_value_type() |
| else: |
| webkit_ipc_types[cpp_type] = cpp_type.get_value_type() |
| # The input to the generators is list of functions to remote. |
| # Run the various generators. |
| generators = [ |
| context_proxy_cpp_webkit_ipc_generator(funcs, unimplemented), |
| context_msg_webkit_ipc_generator(funcs), |
| context_cpp_webkit_ipc_generator(funcs), |
| ] |
| for g in generators: |
| g.generate() |
| |
| if options.verbose: |
| print("Implemented:") |
| print("".join(f" {str(i)} final\n" for i in funcs)) |
| print("Unimplemented:") |
| print("".join(f" {str(u)} final\n" for u in unimplemented)) |
| print(f"Implemented: {len(funcs)}, unimplemented: {len(unimplemented)}, total: {len(funcs)+len(unimplemented)}") |
| print("C++ type map to WebKit IPC type map:") |
| for _, t in cpp_types.items(): |
| if t in webkit_ipc_types: |
| print(f" {str(t)} -> {str(webkit_ipc_types[t])}") |
| print("C++ types without WebKit IPC type:") |
| for _, t in cpp_types.items(): |
| if t not in webkit_ipc_types: |
| print(f" {str(t)}") |
| print("WebKit IPC type conversions") |
| for (a, b), converter in webkit_ipc_types_converters.items(): |
| print(f" {str(a)} -> {str(b)} : {converter.__name__}") |
| print("Done.") |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |