• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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