| #!/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/Borrow.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 | |
| ] | |
| 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(Vector<uint64_t> inUseBuffers) -> (uint64_t bufferID, std::optional<WebCore::DMABufBufferAttributes> dmabufAttributes, UnixFileDescriptor fenceFD, Vector<uint64_t> drawingBufferIDs) Synchronous NotStreamEncodableReply | |
| #endif | |
| #if !PLATFORM(COCOA) && !USE(GRAPHICS_LAYER_WC) && !USE(GBM) | |
| void PrepareForDisplay() -> () Synchronous | |
| #endif | |
| void EnsureExtensionEnabled(WebCore::GCGLExtension extension) StreamBatched | |
| void GetErrors() -> (GCGLErrorCodeSet returnValue) Synchronous | |
| void CopyNativeImage(enum:bool WebCore::GraphicsContextGLSurfaceBuffer buffer, WebKit::RemoteNativeImageReference nativeImageReference) | |
| #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 type, bool unpackFlipY, bool unpackPremultiplyAlpha) -> (bool success) Synchronous NotStreamEncodable | |
| void SetSharedVideoFrameSemaphore(IPC::Semaphore semaphore) NotStreamEncodable | |
| void SetSharedVideoFrameMemory(WebCore::SharedMemory::Handle storageHandle) NotStreamEncodable | |
| [EnabledBy=AllowTestOnlyIPC] void GetLastVideoUploadForTesting() -> (struct WebCore::GraphicsContextGLVideoUploadRecord record) Synchronous | |
| #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) StreamBatched | |
| void DrawBuffersEXT(std::span<const uint32_t> bufs) StreamBatched | |
| 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::ColorSpace 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&&"}) | |
| stream_batched_msg_names = set([ | |
| "ActiveTexture", | |
| "AttachShader", | |
| "BindAttribLocation", | |
| "BindBuffer", | |
| "BindBufferBase", | |
| "BindBufferRange", | |
| "BindExternalImage", | |
| "BindFramebuffer", | |
| "BindRenderbuffer", | |
| "BindSampler", | |
| "BindTexture", | |
| "BindTransformFeedback", | |
| "BindVertexArray", | |
| "BlendColor", | |
| "BlendEquation", | |
| "BlendEquationSeparate", | |
| "BlendEquationSeparateiOES", | |
| "BlendEquationiOES", | |
| "BlendFunc", | |
| "BlendFuncSeparate", | |
| "BlendFuncSeparateiOES", | |
| "BlendFunciOES", | |
| "ClearColor", | |
| "ClearDepth", | |
| "ClearStencil", | |
| "ClipControlEXT", | |
| "ColorMask", | |
| "ColorMaskiOES", | |
| "CreateBuffer", | |
| "CreateFramebuffer", | |
| "CreateProgram", | |
| "CreateQuery", | |
| "CreateQueryEXT", | |
| "CreateRenderbuffer", | |
| "CreateSampler", | |
| "CreateShader", | |
| "CreateTexture", | |
| "CreateTransformFeedback", | |
| "CreateVertexArray", | |
| "CullFace", | |
| "DepthFunc", | |
| "DepthMask", | |
| "DepthRange", | |
| "DetachShader", | |
| "Disable", | |
| "DisableFoveation", | |
| "DisableVertexAttribArray", | |
| "DisableiOES", | |
| "Enable", | |
| "EnableFoveation", | |
| "EnableVertexAttribArray", | |
| "EnableiOES", | |
| "FramebufferRenderbuffer", | |
| "FramebufferResolveRenderbuffer", | |
| "FramebufferTexture2D", | |
| "FramebufferTextureLayer", | |
| "FrontFace", | |
| "Hint", | |
| "LineWidth", | |
| "PixelStorei", | |
| "PolygonModeANGLE", | |
| "PolygonOffset", | |
| "PolygonOffsetClampEXT", | |
| "ProvokingVertexANGLE", | |
| "QueryCounterEXT", | |
| "ReadBuffer", | |
| "RenderbufferStorage", | |
| "RenderbufferStorageMultisample", | |
| "RenderbufferStorageMultisampleANGLE", | |
| "SampleCoverage", | |
| "SamplerParameterf", | |
| "SamplerParameteri", | |
| "Scissor", | |
| "ShaderSource", | |
| "StencilFunc", | |
| "StencilFuncSeparate", | |
| "StencilMask", | |
| "StencilMaskSeparate", | |
| "StencilOp", | |
| "StencilOpSeparate", | |
| "TexParameterf", | |
| "TexParameteri", | |
| "TransformFeedbackVaryings", | |
| "Uniform1f", | |
| "Uniform1fv", | |
| "Uniform1i", | |
| "Uniform1iv", | |
| "Uniform1ui", | |
| "Uniform1uiv", | |
| "Uniform2f", | |
| "Uniform2fv", | |
| "Uniform2i", | |
| "Uniform2iv", | |
| "Uniform2ui", | |
| "Uniform2uiv", | |
| "Uniform3f", | |
| "Uniform3fv", | |
| "Uniform3i", | |
| "Uniform3iv", | |
| "Uniform3ui", | |
| "Uniform3uiv", | |
| "Uniform4f", | |
| "Uniform4fv", | |
| "Uniform4i", | |
| "Uniform4iv", | |
| "Uniform4ui", | |
| "Uniform4uiv", | |
| "UniformBlockBinding", | |
| "UniformMatrix2fv", | |
| "UniformMatrix2x3fv", | |
| "UniformMatrix2x4fv", | |
| "UniformMatrix3fv", | |
| "UniformMatrix3x2fv", | |
| "UniformMatrix3x4fv", | |
| "UniformMatrix4fv", | |
| "UniformMatrix4x2fv", | |
| "UniformMatrix4x3fv", | |
| "VertexAttrib1f", | |
| "VertexAttrib1fv", | |
| "VertexAttrib2f", | |
| "VertexAttrib2fv", | |
| "VertexAttrib3f", | |
| "VertexAttrib3fv", | |
| "VertexAttrib4f", | |
| "VertexAttrib4fv", | |
| "VertexAttribDivisor", | |
| "VertexAttribI4i", | |
| "VertexAttribI4iv", | |
| "VertexAttribI4ui", | |
| "VertexAttribI4uiv", | |
| "VertexAttribIPointer", | |
| "VertexAttribPointer", | |
| "Viewport", | |
| ]) | |
| 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"] | |
| if self.name in stream_batched_msg_names: | |
| self.tags += ["StreamBatched"] | |
| 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"protect(m_context)->{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"if (!{a.name}) [[unlikely]]", | |
| f" return;", | |
| f"{a.name} = m_objectNames.take({a.name});", | |
| ] | |
| else: | |
| self.pre_call_stmts += [ | |
| 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)}(FillWith {{ }}, {a.name}Size, 0);"] | |
| borrowed_name = f"borrowed{a.name[0].upper()}{a.name[1:]}" | |
| self.pre_call_stmts += [f"Borrow {borrowed_name} = {store_arg.name};"] | |
| self.in_exprs += [cpp_expr(store_arg.type, f"{borrowed_name}->mutableSpan()")] | |
| webkit_ipc_type = webkit_ipc_types[a.type] | |
| self.out_exprs += [webkit_ipc_convert_expr(cpp_expr(store_arg.type, borrowed_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.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()) |