1 //* Copyright 2019 The Dawn Authors 2 //* 3 //* Licensed under the Apache License, Version 2.0 (the "License"); 4 //* you may not use this file except in compliance with the License. 5 //* You may obtain a copy of the License at 6 //* 7 //* http://www.apache.org/licenses/LICENSE-2.0 8 //* 9 //* Unless required by applicable law or agreed to in writing, software 10 //* distributed under the License is distributed on an "AS IS" BASIS, 11 //* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 //* See the License for the specific language governing permissions and 13 //* limitations under the License. 14 15 #include "common/Log.h" 16 #include "dawn_wire/client/ApiObjects.h" 17 #include "dawn_wire/client/Client.h" 18 19 #include <algorithm> 20 #include <cstring> 21 #include <string> 22 #include <vector> 23 24 namespace dawn_wire { namespace client { 25 26 //* Outputs an rvalue that's the number of elements a pointer member points to. 27 {% macro member_length(member, accessor) -%} 28 {%- if member.length == "constant" -%} 29 {{member.constant_length}} 30 {%- else -%} 31 {{accessor}}{{as_varName(member.length.name)}} 32 {%- endif -%} 33 {%- endmacro %} 34 35 //* Implementation of the client API functions. 36 {% for type in by_category["object"] %} 37 {% set Type = type.name.CamelCase() %} 38 {% set cType = as_cType(type.name) %} 39 40 {% for method in type.methods %} 41 {% set Suffix = as_MethodSuffix(type.name, method.name) %} 42 43 {% if Suffix in client_handwritten_commands %} 44 static 45 {% endif %} 46 {{as_cType(method.return_type.name)}} Client{{Suffix}}( 47 {{-cType}} cSelf 48 {%- for arg in method.arguments -%} 49 , {{as_annotated_cType(arg)}} 50 {%- endfor -%} 51 ) { 52 auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf); 53 {% if Suffix not in client_handwritten_commands %} 54 {{Suffix}}Cmd cmd; 55 56 //* Create the structure going on the wire on the stack and fill it with the value 57 //* arguments so it can compute its size. 58 cmd.self = cSelf; 59 60 //* For object creation, store the object ID the client will use for the result. 61 {% if method.return_type.category == "object" %} 62 auto* allocation = self->client->{{method.return_type.name.CamelCase()}}Allocator().New(self->client); 63 cmd.result = ObjectHandle{allocation->object->id, allocation->generation}; 64 {% endif %} 65 66 {% for arg in method.arguments %} 67 cmd.{{as_varName(arg.name)}} = {{as_varName(arg.name)}}; 68 {% endfor %} 69 70 //* Allocate space to send the command and copy the value args over. 71 self->client->SerializeCommand(cmd); 72 73 {% if method.return_type.category == "object" %} 74 return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get()); 75 {% endif %} 76 {% else %} 77 return self->{{method.name.CamelCase()}}( 78 {%- for arg in method.arguments -%} 79 {%if not loop.first %}, {% endif %} {{as_varName(arg.name)}} 80 {%- endfor -%}); 81 {% endif %} 82 } 83 {% endfor %} 84 85 //* When an object's refcount reaches 0, notify the server side of it and delete it. 86 void Client{{as_MethodSuffix(type.name, Name("release"))}}({{cType}} cObj) { 87 {{Type}}* obj = reinterpret_cast<{{Type}}*>(cObj); 88 obj->refcount --; 89 90 if (obj->refcount > 0) { 91 return; 92 } 93 94 DestroyObjectCmd cmd; 95 cmd.objectType = ObjectType::{{type.name.CamelCase()}}; 96 cmd.objectId = obj->id; 97 98 obj->client->SerializeCommand(cmd); 99 obj->client->{{type.name.CamelCase()}}Allocator().Free(obj); 100 } 101 102 void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) { 103 {{Type}}* obj = reinterpret_cast<{{Type}}*>(cObj); 104 obj->refcount ++; 105 } 106 {% endfor %} 107 108 namespace { 109 WGPUInstance ClientCreateInstance(WGPUInstanceDescriptor const* descriptor) { 110 UNREACHABLE(); 111 return nullptr; 112 } 113 114 struct ProcEntry { 115 WGPUProc proc; 116 const char* name; 117 }; 118 static const ProcEntry sProcMap[] = { 119 {% for (type, method) in c_methods_sorted_by_name %} 120 { reinterpret_cast<WGPUProc>(Client{{as_MethodSuffix(type.name, method.name)}}), "{{as_cMethod(type.name, method.name)}}" }, 121 {% endfor %} 122 }; 123 static constexpr size_t sProcMapSize = sizeof(sProcMap) / sizeof(sProcMap[0]); 124 } // anonymous namespace 125 126 WGPUProc ClientGetProcAddress(WGPUDevice, const char* procName) { 127 if (procName == nullptr) { 128 return nullptr; 129 } 130 131 const ProcEntry* entry = std::lower_bound(&sProcMap[0], &sProcMap[sProcMapSize], procName, 132 [](const ProcEntry &a, const char *b) -> bool { 133 return strcmp(a.name, b) < 0; 134 } 135 ); 136 137 if (entry != &sProcMap[sProcMapSize] && strcmp(entry->name, procName) == 0) { 138 return entry->proc; 139 } 140 141 // Special case the two free-standing functions of the API. 142 if (strcmp(procName, "wgpuGetProcAddress") == 0) { 143 return reinterpret_cast<WGPUProc>(ClientGetProcAddress); 144 } 145 146 if (strcmp(procName, "wgpuCreateInstance") == 0) { 147 return reinterpret_cast<WGPUProc>(ClientCreateInstance); 148 } 149 150 return nullptr; 151 } 152 153 std::vector<const char*> GetProcMapNamesForTesting() { 154 std::vector<const char*> result; 155 result.reserve(sProcMapSize); 156 for (const ProcEntry& entry : sProcMap) { 157 result.push_back(entry.name); 158 } 159 return result; 160 } 161 162 {% set Prefix = metadata.proc_table_prefix %} 163 static {{Prefix}}ProcTable gProcTable = { 164 {% for function in by_category["function"] %} 165 Client{{as_cppType(function.name)}}, 166 {% endfor %} 167 {% for type in by_category["object"] %} 168 {% for method in c_methods(type) %} 169 Client{{as_MethodSuffix(type.name, method.name)}}, 170 {% endfor %} 171 {% endfor %} 172 }; 173 const {{Prefix}}ProcTable& GetProcs() { 174 return gProcTable; 175 } 176 }} // namespace dawn_wire::client 177