dawn_wire::server: Simplify ForwardToServer usage with C++17

This uses template parameter type deduction to pass the member function
pointer and then extract the types that compose it. Which means that the
member function pointer only needs to be written once.

The order of arguments of the Server::On*Callback methods is changed to
put the userdata first. This helps make template type deduction simpler.

Bug: dawn:824
Change-Id: I4e2bc33dfd52a11620dea51b40508eca6c878d72
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/75071
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2022-01-06 09:09:49 +00:00 committed by Dawn LUCI CQ
parent 2994d2e7b9
commit 31f12242da
7 changed files with 75 additions and 111 deletions

View File

@ -42,13 +42,11 @@ namespace dawn_wire { namespace server {
// auto userdata = MakeUserdata<MyUserdata>();
// userdata->foo = 2;
//
// // TODO(enga): Make the template inference for ForwardToServer cleaner with C++17
// callMyCallbackHandler(
// ForwardToServer<decltype(&Server::MyCallbackHandler)>::Func<
// &Server::MyCallbackHandler>(),
// ForwardToServer<&Server::MyCallbackHandler>,
// userdata.release());
//
// void Server::MyCallbackHandler(MyUserdata* userdata) { }
// void Server::MyCallbackHandler(MyUserdata* userdata, Other args) { }
struct CallbackUserdata {
Server* const server;
std::weak_ptr<bool> const serverIsAlive;
@ -59,53 +57,35 @@ namespace dawn_wire { namespace server {
}
};
template <typename F>
class ForwardToServer;
template <auto F>
struct ForwardToServerHelper {
template <typename _>
struct ExtractedTypes;
template <typename R, typename... Args>
class ForwardToServer<R (Server::*)(Args...)> {
private:
// Get the type T of the last argument. It has CallbackUserdata as its base.
using UserdataT = typename std::remove_pointer<typename std::decay<decltype(
std::get<sizeof...(Args) - 1>(std::declval<std::tuple<Args...>>()))>::type>::type;
static_assert(std::is_base_of<CallbackUserdata, UserdataT>::value,
"Last argument of callback handler should derive from CallbackUserdata.");
template <class T, class... Ts>
struct UntypedCallbackImpl;
template <std::size_t... I, class... Ts>
struct UntypedCallbackImpl<std::index_sequence<I...>, Ts...> {
template <R (Server::*Func)(Args...)>
static auto ForwardToServer(
// Unpack and forward the types of the parameter pack.
// Append void* as the last argument.
typename std::tuple_element<I, std::tuple<Ts...>>::type... args,
void* userdata) {
// An internal structure used to unpack the various types that compose the type of F
template <typename Return, typename Class, typename Userdata, typename... Args>
struct ExtractedTypes<Return (Class::*)(Userdata*, Args...)> {
using UntypedCallback = Return (*)(Args..., void*);
static Return Callback(Args... args, void* userdata) {
// Acquire the userdata, and cast it to UserdataT.
std::unique_ptr<UserdataT> data(static_cast<UserdataT*>(userdata));
std::unique_ptr<Userdata> data(static_cast<Userdata*>(userdata));
if (data->serverIsAlive.expired()) {
// Do nothing if the server has already been destroyed.
return;
}
// Forward the arguments and the typed userdata to the Server:: member function.
(data->server->*Func)(std::forward<decltype(args)>(args)..., data.get());
(data->server->*F)(data.get(), std::forward<decltype(args)>(args)...);
}
};
// Generate a free function which has all of the same arguments, except the last
// userdata argument is void* instead of UserdataT*. Dawn's userdata args are void*.
using UntypedCallback =
UntypedCallbackImpl<std::make_index_sequence<sizeof...(Args) - 1>, Args...>;
public:
template <R (Server::*F)(Args...)>
static auto Func() {
return UntypedCallback::template ForwardToServer<F>;
static constexpr typename ExtractedTypes<decltype(F)>::UntypedCallback Create() {
return ExtractedTypes<decltype(F)>::Callback;
}
};
template <auto F>
constexpr auto ForwardToServer = ForwardToServerHelper<F>::Create();
struct MapUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
@ -217,30 +197,30 @@ namespace dawn_wire { namespace server {
void OnUncapturedError(ObjectHandle device, WGPUErrorType type, const char* message);
void OnDeviceLost(ObjectHandle device, WGPUDeviceLostReason reason, const char* message);
void OnLogging(ObjectHandle device, WGPULoggingType type, const char* message);
void OnDevicePopErrorScope(WGPUErrorType type,
const char* message,
ErrorScopeUserdata* userdata);
void OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* userdata);
void OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* userdata);
void OnCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
void OnDevicePopErrorScope(ErrorScopeUserdata* userdata,
WGPUErrorType type,
const char* message);
void OnBufferMapAsyncCallback(MapUserdata* userdata, WGPUBufferMapAsyncStatus status);
void OnQueueWorkDone(QueueWorkDoneUserdata* userdata, WGPUQueueWorkDoneStatus status);
void OnCreateComputePipelineAsyncCallback(CreatePipelineAsyncUserData* userdata,
WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,
const char* message,
CreatePipelineAsyncUserData* userdata);
void OnCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
const char* message);
void OnCreateRenderPipelineAsyncCallback(CreatePipelineAsyncUserData* userdata,
WGPUCreatePipelineAsyncStatus status,
WGPURenderPipeline pipeline,
const char* message,
CreatePipelineAsyncUserData* userdata);
void OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info,
ShaderModuleGetCompilationInfoUserdata* userdata);
void OnRequestAdapterCallback(WGPURequestAdapterStatus status,
const char* message);
void OnShaderModuleGetCompilationInfo(ShaderModuleGetCompilationInfoUserdata* userdata,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info);
void OnRequestAdapterCallback(RequestAdapterUserdata* userdata,
WGPURequestAdapterStatus status,
WGPUAdapter adapter,
const char* message,
RequestAdapterUserdata* userdata);
void OnRequestDeviceCallback(WGPURequestDeviceStatus status,
const char* message);
void OnRequestDeviceCallback(RequestDeviceUserdata* userdata,
WGPURequestDeviceStatus status,
WGPUDevice device,
const char* message,
RequestDeviceUserdata* userdata);
const char* message);
#include "dawn_wire/server/ServerPrototypes_autogen.inc"

View File

@ -39,18 +39,16 @@ namespace dawn_wire { namespace server {
userdata->requestSerial = requestSerial;
userdata->deviceObjectId = deviceHandle.id;
mProcs.adapterRequestDevice(
adapter->handle, descriptor,
ForwardToServer<decltype(
&Server::OnRequestDeviceCallback)>::Func<&Server::OnRequestDeviceCallback>(),
userdata.release());
mProcs.adapterRequestDevice(adapter->handle, descriptor,
ForwardToServer<&Server::OnRequestDeviceCallback>,
userdata.release());
return true;
}
void Server::OnRequestDeviceCallback(WGPURequestDeviceStatus status,
void Server::OnRequestDeviceCallback(RequestDeviceUserdata* data,
WGPURequestDeviceStatus status,
WGPUDevice device,
const char* message,
RequestDeviceUserdata* data) {
const char* message) {
auto* deviceObject = DeviceObjects().Get(data->deviceObjectId, AllocationState::Reserved);
// Should be impossible to fail. ObjectIds can't be freed by a destroy command until
// they move from Reserved to Allocated, or if they are destroyed here.

View File

@ -80,7 +80,7 @@ namespace dawn_wire { namespace server {
// client does the default size computation, we should always have a valid actual size here
// in server. All other invalid actual size can be caught by dawn native side validation.
if (offset64 > std::numeric_limits<size_t>::max() || size64 >= WGPU_WHOLE_MAP_SIZE) {
OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus_Error, userdata.get());
OnBufferMapAsyncCallback(userdata.get(), WGPUBufferMapAsyncStatus_Error);
return true;
}
@ -90,11 +90,9 @@ namespace dawn_wire { namespace server {
userdata->offset = offset;
userdata->size = size;
mProcs.bufferMapAsync(
buffer->handle, mode, offset, size,
ForwardToServer<decltype(
&Server::OnBufferMapAsyncCallback)>::Func<&Server::OnBufferMapAsyncCallback>(),
userdata.release());
mProcs.bufferMapAsync(buffer->handle, mode, offset, size,
ForwardToServer<&Server::OnBufferMapAsyncCallback>,
userdata.release());
return true;
}
@ -227,7 +225,7 @@ namespace dawn_wire { namespace server {
static_cast<size_t>(offset), static_cast<size_t>(size));
}
void Server::OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* data) {
void Server::OnBufferMapAsyncCallback(MapUserdata* data, WGPUBufferMapAsyncStatus status) {
// Skip sending the callback if the buffer has already been destroyed.
auto* bufferData = BufferObjects().Get(data->buffer.id);
if (bufferData == nullptr || bufferData->generation != data->buffer.generation) {

View File

@ -91,19 +91,16 @@ namespace dawn_wire { namespace server {
ErrorScopeUserdata* unownedUserdata = userdata.release();
bool success = mProcs.devicePopErrorScope(
device->handle,
ForwardToServer<decltype(
&Server::OnDevicePopErrorScope)>::Func<&Server::OnDevicePopErrorScope>(),
unownedUserdata);
device->handle, ForwardToServer<&Server::OnDevicePopErrorScope>, unownedUserdata);
if (!success) {
delete unownedUserdata;
}
return success;
}
void Server::OnDevicePopErrorScope(WGPUErrorType type,
const char* message,
ErrorScopeUserdata* userdata) {
void Server::OnDevicePopErrorScope(ErrorScopeUserdata* userdata,
WGPUErrorType type,
const char* message) {
ReturnDevicePopErrorScopeCallbackCmd cmd;
cmd.device = userdata->device;
cmd.requestSerial = userdata->requestSerial;
@ -139,16 +136,14 @@ namespace dawn_wire { namespace server {
mProcs.deviceCreateComputePipelineAsync(
device->handle, descriptor,
ForwardToServer<decltype(&Server::OnCreateComputePipelineAsyncCallback)>::Func<
&Server::OnCreateComputePipelineAsyncCallback>(),
userdata.release());
ForwardToServer<&Server::OnCreateComputePipelineAsyncCallback>, userdata.release());
return true;
}
void Server::OnCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
void Server::OnCreateComputePipelineAsyncCallback(CreatePipelineAsyncUserData* data,
WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,
const char* message,
CreatePipelineAsyncUserData* data) {
const char* message) {
HandleCreateRenderPipelineAsyncCallbackResult<ObjectType::ComputePipeline>(
&ComputePipelineObjects(), status, pipeline, data);
@ -186,16 +181,14 @@ namespace dawn_wire { namespace server {
mProcs.deviceCreateRenderPipelineAsync(
device->handle, descriptor,
ForwardToServer<decltype(&Server::OnCreateRenderPipelineAsyncCallback)>::Func<
&Server::OnCreateRenderPipelineAsyncCallback>(),
userdata.release());
ForwardToServer<&Server::OnCreateRenderPipelineAsyncCallback>, userdata.release());
return true;
}
void Server::OnCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
void Server::OnCreateRenderPipelineAsyncCallback(CreatePipelineAsyncUserData* data,
WGPUCreatePipelineAsyncStatus status,
WGPURenderPipeline pipeline,
const char* message,
CreatePipelineAsyncUserData* data) {
const char* message) {
HandleCreateRenderPipelineAsyncCallbackResult<ObjectType::RenderPipeline>(
&RenderPipelineObjects(), status, pipeline, data);

View File

@ -41,18 +41,16 @@ namespace dawn_wire { namespace server {
userdata->requestSerial = requestSerial;
userdata->adapterObjectId = adapterHandle.id;
mProcs.instanceRequestAdapter(
instance->handle, options,
ForwardToServer<decltype(
&Server::OnRequestAdapterCallback)>::Func<&Server::OnRequestAdapterCallback>(),
userdata.release());
mProcs.instanceRequestAdapter(instance->handle, options,
ForwardToServer<&Server::OnRequestAdapterCallback>,
userdata.release());
return true;
}
void Server::OnRequestAdapterCallback(WGPURequestAdapterStatus status,
void Server::OnRequestAdapterCallback(RequestAdapterUserdata* data,
WGPURequestAdapterStatus status,
WGPUAdapter adapter,
const char* message,
RequestAdapterUserdata* data) {
const char* message) {
auto* adapterObject =
AdapterObjects().Get(data->adapterObjectId, AllocationState::Reserved);
// Should be impossible to fail. ObjectIds can't be freed by a destroy command until

View File

@ -17,7 +17,7 @@
namespace dawn_wire { namespace server {
void Server::OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* data) {
void Server::OnQueueWorkDone(QueueWorkDoneUserdata* data, WGPUQueueWorkDoneStatus status) {
ReturnQueueWorkDoneCallbackCmd cmd;
cmd.queue = data->queue;
cmd.requestSerial = data->requestSerial;
@ -38,10 +38,9 @@ namespace dawn_wire { namespace server {
userdata->queue = ObjectHandle{queueId, queue->generation};
userdata->requestSerial = requestSerial;
mProcs.queueOnSubmittedWorkDone(
queue->handle, signalValue,
ForwardToServer<decltype(&Server::OnQueueWorkDone)>::Func<&Server::OnQueueWorkDone>(),
userdata.release());
mProcs.queueOnSubmittedWorkDone(queue->handle, signalValue,
ForwardToServer<&Server::OnQueueWorkDone>,
userdata.release());
return true;
}

View File

@ -29,16 +29,14 @@ namespace dawn_wire { namespace server {
userdata->requestSerial = requestSerial;
mProcs.shaderModuleGetCompilationInfo(
shaderModule->handle,
ForwardToServer<decltype(&Server::OnShaderModuleGetCompilationInfo)>::Func<
&Server::OnShaderModuleGetCompilationInfo>(),
shaderModule->handle, ForwardToServer<&Server::OnShaderModuleGetCompilationInfo>,
userdata.release());
return true;
}
void Server::OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info,
ShaderModuleGetCompilationInfoUserdata* data) {
void Server::OnShaderModuleGetCompilationInfo(ShaderModuleGetCompilationInfoUserdata* data,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info) {
ReturnShaderModuleGetCompilationInfoCallbackCmd cmd;
cmd.shaderModule = data->shaderModule;
cmd.requestSerial = data->requestSerial;