tint->dawn: Move src/dawn_wire -> src/dawn/wire

Bug: dawn:1275
Change-Id: I56535bf4d387c4bd423140705ea70812be073eac
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/79081
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Ben Clayton
2022-02-04 12:51:25 +00:00
parent 7d5badd9f4
commit 20cbe6d9e8
103 changed files with 796 additions and 772 deletions

View File

@@ -1,4 +1,4 @@
# Copyright 2019 The Dawn Authors
# Copyright 2022 The Dawn Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,100 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import("../../scripts/dawn_overrides_with_defaults.gni")
import("${dawn_root}/generator/dawn_generator.gni")
import("${dawn_root}/scripts/dawn_component.gni")
# Public dawn_wire headers so they can be publically visible for
# dependencies of dawn_wire
source_set("dawn_wire_headers") {
public_deps = [ "${dawn_root}/src/dawn:dawn_headers" ]
all_dependent_configs = [ "${dawn_root}/src/dawn/common:public_include_dirs" ]
sources = [
"${dawn_root}/src/include/dawn_wire/Wire.h",
"${dawn_root}/src/include/dawn_wire/WireClient.h",
"${dawn_root}/src/include/dawn_wire/WireServer.h",
"${dawn_root}/src/include/dawn_wire/dawn_wire_export.h",
]
################################################################################
# Build target aliases
# TODO(crbug.com/dawn/1275) - remove these
################################################################################
group("dawn_wire") {
public_deps = [ "../dawn/wire" ]
}
dawn_json_generator("dawn_wire_gen") {
target = "dawn_wire"
outputs = [
"src/dawn_wire/ObjectType_autogen.h",
"src/dawn_wire/WireCmd_autogen.h",
"src/dawn_wire/WireCmd_autogen.cpp",
"src/dawn_wire/client/ApiObjects_autogen.h",
"src/dawn_wire/client/ApiProcs_autogen.cpp",
"src/dawn_wire/client/ClientBase_autogen.h",
"src/dawn_wire/client/ClientHandlers_autogen.cpp",
"src/dawn_wire/client/ClientPrototypes_autogen.inc",
"src/dawn_wire/server/ServerBase_autogen.h",
"src/dawn_wire/server/ServerDoers_autogen.cpp",
"src/dawn_wire/server/ServerHandlers_autogen.cpp",
"src/dawn_wire/server/ServerPrototypes_autogen.inc",
]
}
dawn_component("dawn_wire") {
DEFINE_PREFIX = "DAWN_WIRE"
deps = [
":dawn_wire_gen",
"${dawn_root}/src/dawn/common",
]
configs = [ "${dawn_root}/src/dawn/common:internal_config" ]
sources = get_target_outputs(":dawn_wire_gen")
sources += [
"BufferConsumer.h",
"BufferConsumer_impl.h",
"ChunkedCommandHandler.cpp",
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
"SupportedFeatures.cpp",
"SupportedFeatures.h",
"Wire.cpp",
"WireClient.cpp",
"WireDeserializeAllocator.cpp",
"WireDeserializeAllocator.h",
"WireResult.h",
"WireServer.cpp",
"client/Adapter.cpp",
"client/Adapter.h",
"client/ApiObjects.h",
"client/Buffer.cpp",
"client/Buffer.h",
"client/Client.cpp",
"client/Client.h",
"client/ClientDoers.cpp",
"client/ClientInlineMemoryTransferService.cpp",
"client/Device.cpp",
"client/Device.h",
"client/Instance.cpp",
"client/Instance.h",
"client/LimitsAndFeatures.cpp",
"client/LimitsAndFeatures.h",
"client/ObjectAllocator.h",
"client/Queue.cpp",
"client/Queue.h",
"client/RequestTracker.h",
"client/ShaderModule.cpp",
"client/ShaderModule.h",
"server/ObjectStorage.h",
"server/Server.cpp",
"server/Server.h",
"server/ServerAdapter.cpp",
"server/ServerBuffer.cpp",
"server/ServerDevice.cpp",
"server/ServerInlineMemoryTransferService.cpp",
"server/ServerInstance.cpp",
"server/ServerQueue.cpp",
"server/ServerShaderModule.cpp",
]
# Make headers publicly visible
public_deps = [ ":dawn_wire_headers" ]
group("dawn_wire_headers") {
public_deps = [ "../dawn/wire:headers" ]
}

View File

@@ -1,85 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_BUFFERCONSUMER_H_
#define DAWNWIRE_BUFFERCONSUMER_H_
#include "dawn_wire/WireResult.h"
#include <cstddef>
namespace dawn::wire {
// BufferConsumer is a utility class that allows reading bytes from a buffer
// while simultaneously decrementing the amount of remaining space by exactly
// the amount read. It helps prevent bugs where incrementing a pointer and
// decrementing a size value are not kept in sync.
// BufferConsumer also contains bounds checks to prevent reading out-of-bounds.
template <typename BufferT>
class BufferConsumer {
static_assert(sizeof(BufferT) == 1,
"BufferT must be 1-byte, but may have const/volatile qualifiers.");
public:
BufferConsumer(BufferT* buffer, size_t size) : mBuffer(buffer), mSize(size) {
}
BufferT* Buffer() const {
return mBuffer;
}
size_t AvailableSize() const {
return mSize;
}
protected:
template <typename T, typename N>
WireResult NextN(N count, T** data);
template <typename T>
WireResult Next(T** data);
template <typename T>
WireResult Peek(T** data);
private:
BufferT* mBuffer;
size_t mSize;
};
class SerializeBuffer : public BufferConsumer<char> {
public:
using BufferConsumer::BufferConsumer;
using BufferConsumer::Next;
using BufferConsumer::NextN;
};
class DeserializeBuffer : public BufferConsumer<const volatile char> {
public:
using BufferConsumer::BufferConsumer;
using BufferConsumer::Peek;
template <typename T, typename N>
WireResult ReadN(N count, const volatile T** data) {
return NextN(count, data);
}
template <typename T>
WireResult Read(const volatile T** data) {
return Next(data);
}
};
} // namespace dawn::wire
#endif // DAWNWIRE_BUFFERCONSUMER_H_

View File

@@ -1,73 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_BUFFERCONSUMER_IMPL_H_
#define DAWNWIRE_BUFFERCONSUMER_IMPL_H_
#include "dawn_wire/BufferConsumer.h"
#include <limits>
#include <type_traits>
namespace dawn::wire {
template <typename BufferT>
template <typename T>
WireResult BufferConsumer<BufferT>::Peek(T** data) {
if (sizeof(T) > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
return WireResult::Success;
}
template <typename BufferT>
template <typename T>
WireResult BufferConsumer<BufferT>::Next(T** data) {
if (sizeof(T) > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += sizeof(T);
mSize -= sizeof(T);
return WireResult::Success;
}
template <typename BufferT>
template <typename T, typename N>
WireResult BufferConsumer<BufferT>::NextN(N count, T** data) {
static_assert(std::is_unsigned<N>::value, "|count| argument of NextN must be unsigned.");
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
if (count > kMaxCountWithoutOverflows) {
return WireResult::FatalError;
}
// Cannot overflow because |count| is not greater than |kMaxCountWithoutOverflows|.
size_t totalSize = sizeof(T) * count;
if (totalSize > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += totalSize;
mSize -= totalSize;
return WireResult::Success;
}
} // namespace dawn::wire
#endif // DAWNWIRE_BUFFERCONSUMER_IMPL_H_

View File

@@ -1,83 +0,0 @@
# Copyright 2020 The Dawn Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
DawnJSONGenerator(
TARGET "dawn_wire"
PRINT_NAME "Dawn wire"
RESULT_VARIABLE "DAWN_WIRE_GEN_SOURCES"
)
add_library(dawn_wire ${DAWN_DUMMY_FILE})
target_compile_definitions(dawn_wire PRIVATE "DAWN_WIRE_IMPLEMENTATION")
if(BUILD_SHARED_LIBS)
target_compile_definitions(dawn_wire PRIVATE "DAWN_WIRE_SHARED_LIBRARY")
endif()
target_sources(dawn_wire PRIVATE
"${DAWN_INCLUDE_DIR}/dawn_wire/Wire.h"
"${DAWN_INCLUDE_DIR}/dawn_wire/WireClient.h"
"${DAWN_INCLUDE_DIR}/dawn_wire/WireServer.h"
"${DAWN_INCLUDE_DIR}/dawn_wire/dawn_wire_export.h"
${DAWN_WIRE_GEN_SOURCES}
"BufferConsumer.h"
"BufferConsumer_impl.h"
"ChunkedCommandHandler.cpp"
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
"SupportedFeatures.cpp"
"SupportedFeatures.h"
"Wire.cpp"
"WireClient.cpp"
"WireDeserializeAllocator.cpp"
"WireDeserializeAllocator.h"
"WireResult.h"
"WireServer.cpp"
"client/Adapter.cpp"
"client/Adapter.h"
"client/ApiObjects.h"
"client/Buffer.cpp"
"client/Buffer.h"
"client/Client.cpp"
"client/Client.h"
"client/ClientDoers.cpp"
"client/ClientInlineMemoryTransferService.cpp"
"client/Device.cpp"
"client/Device.h"
"client/Instance.cpp"
"client/Instance.h"
"client/LimitsAndFeatures.cpp"
"client/LimitsAndFeatures.h"
"client/ObjectAllocator.h"
"client/Queue.cpp"
"client/Queue.h"
"client/RequestTracker.h"
"client/ShaderModule.cpp"
"client/ShaderModule.h"
"server/ObjectStorage.h"
"server/Server.cpp"
"server/Server.h"
"server/ServerAdapter.cpp"
"server/ServerBuffer.cpp"
"server/ServerDevice.cpp"
"server/ServerInlineMemoryTransferService.cpp"
"server/ServerInstance.cpp"
"server/ServerQueue.cpp"
"server/ServerShaderModule.cpp"
)
target_link_libraries(dawn_wire
PUBLIC dawn_headers
PRIVATE dawn_common dawn_internal_config
)

View File

@@ -1,79 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/ChunkedCommandHandler.h"
#include "dawn/common/Alloc.h"
#include <algorithm>
#include <cstring>
namespace dawn::wire {
ChunkedCommandHandler::~ChunkedCommandHandler() = default;
const volatile char* ChunkedCommandHandler::HandleCommands(const volatile char* commands,
size_t size) {
if (mChunkedCommandRemainingSize > 0) {
// If there is a chunked command in flight, append the command data.
// We append at most |mChunkedCommandRemainingSize| which is enough to finish the
// in-flight chunked command, and then pass the rest along to a second call to
// |HandleCommandsImpl|.
size_t chunkSize = std::min(size, mChunkedCommandRemainingSize);
memcpy(mChunkedCommandData.get() + mChunkedCommandPutOffset,
const_cast<const char*>(commands), chunkSize);
mChunkedCommandPutOffset += chunkSize;
mChunkedCommandRemainingSize -= chunkSize;
commands += chunkSize;
size -= chunkSize;
if (mChunkedCommandRemainingSize == 0) {
// Once the chunked command is complete, pass the data to the command handler
// implemenation.
auto chunkedCommandData = std::move(mChunkedCommandData);
if (HandleCommandsImpl(chunkedCommandData.get(), mChunkedCommandPutOffset) ==
nullptr) {
// |HandleCommandsImpl| returns nullptr on error. Forward any errors
// out.
return nullptr;
}
}
}
return HandleCommandsImpl(commands, size);
}
ChunkedCommandHandler::ChunkedCommandsResult ChunkedCommandHandler::BeginChunkedCommandData(
const volatile char* commands,
size_t commandSize,
size_t initialSize) {
ASSERT(!mChunkedCommandData);
// Reserve space for all the command data we're expecting, and copy the initial data
// to the start of the memory.
mChunkedCommandData.reset(AllocNoThrow<char>(commandSize));
if (!mChunkedCommandData) {
return ChunkedCommandsResult::Error;
}
memcpy(mChunkedCommandData.get(), const_cast<const char*>(commands), initialSize);
mChunkedCommandPutOffset = initialSize;
mChunkedCommandRemainingSize = commandSize - initialSize;
return ChunkedCommandsResult::Consumed;
}
} // namespace dawn::wire

View File

@@ -1,71 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CHUNKEDCOMMANDHANDLER_H_
#define DAWNWIRE_CHUNKEDCOMMANDHANDLER_H_
#include "dawn/common/Assert.h"
#include "dawn_wire/Wire.h"
#include "dawn_wire/WireCmd_autogen.h"
#include <cstdint>
#include <memory>
namespace dawn::wire {
class ChunkedCommandHandler : public CommandHandler {
public:
const volatile char* HandleCommands(const volatile char* commands, size_t size) override;
~ChunkedCommandHandler() override;
protected:
enum class ChunkedCommandsResult {
Passthrough,
Consumed,
Error,
};
// Returns |true| if the commands were entirely consumed into the chunked command vector
// and should be handled later once we receive all the command data.
// Returns |false| if commands should be handled now immediately.
ChunkedCommandsResult HandleChunkedCommands(const volatile char* commands, size_t size) {
uint64_t commandSize64 =
reinterpret_cast<const volatile CmdHeader*>(commands)->commandSize;
if (commandSize64 > std::numeric_limits<size_t>::max()) {
return ChunkedCommandsResult::Error;
}
size_t commandSize = static_cast<size_t>(commandSize64);
if (size < commandSize) {
return BeginChunkedCommandData(commands, commandSize, size);
}
return ChunkedCommandsResult::Passthrough;
}
private:
virtual const volatile char* HandleCommandsImpl(const volatile char* commands,
size_t size) = 0;
ChunkedCommandsResult BeginChunkedCommandData(const volatile char* commands,
size_t commandSize,
size_t initialSize);
size_t mChunkedCommandRemainingSize = 0;
size_t mChunkedCommandPutOffset = 0;
std::unique_ptr<char[]> mChunkedCommandData;
};
} // namespace dawn::wire
#endif // DAWNWIRE_CHUNKEDCOMMANDHANDLER_H_

View File

@@ -1,38 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/ChunkedCommandSerializer.h"
namespace dawn::wire {
ChunkedCommandSerializer::ChunkedCommandSerializer(CommandSerializer* serializer)
: mSerializer(serializer), mMaxAllocationSize(serializer->GetMaximumAllocationSize()) {
}
void ChunkedCommandSerializer::SerializeChunkedCommand(const char* allocatedBuffer,
size_t remainingSize) {
while (remainingSize > 0) {
size_t chunkSize = std::min(remainingSize, mMaxAllocationSize);
void* dst = mSerializer->GetCmdSpace(chunkSize);
if (dst == nullptr) {
return;
}
memcpy(dst, allocatedBuffer, chunkSize);
allocatedBuffer += chunkSize;
remainingSize -= chunkSize;
}
}
} // namespace dawn::wire

View File

@@ -1,114 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CHUNKEDCOMMANDSERIALIZER_H_
#define DAWNWIRE_CHUNKEDCOMMANDSERIALIZER_H_
#include "dawn/common/Alloc.h"
#include "dawn/common/Compiler.h"
#include "dawn_wire/Wire.h"
#include "dawn_wire/WireCmd_autogen.h"
#include <algorithm>
#include <cstring>
#include <memory>
namespace dawn::wire {
class ChunkedCommandSerializer {
public:
ChunkedCommandSerializer(CommandSerializer* serializer);
template <typename Cmd>
void SerializeCommand(const Cmd& cmd) {
SerializeCommand(cmd, 0, [](SerializeBuffer*) { return WireResult::Success; });
}
template <typename Cmd, typename ExtraSizeSerializeFn>
void SerializeCommand(const Cmd& cmd,
size_t extraSize,
ExtraSizeSerializeFn&& SerializeExtraSize) {
SerializeCommandImpl(
cmd,
[](const Cmd& cmd, size_t requiredSize, SerializeBuffer* serializeBuffer) {
return cmd.Serialize(requiredSize, serializeBuffer);
},
extraSize, std::forward<ExtraSizeSerializeFn>(SerializeExtraSize));
}
template <typename Cmd>
void SerializeCommand(const Cmd& cmd, const ObjectIdProvider& objectIdProvider) {
SerializeCommand(cmd, objectIdProvider, 0,
[](SerializeBuffer*) { return WireResult::Success; });
}
template <typename Cmd, typename ExtraSizeSerializeFn>
void SerializeCommand(const Cmd& cmd,
const ObjectIdProvider& objectIdProvider,
size_t extraSize,
ExtraSizeSerializeFn&& SerializeExtraSize) {
SerializeCommandImpl(
cmd,
[&objectIdProvider](const Cmd& cmd, size_t requiredSize,
SerializeBuffer* serializeBuffer) {
return cmd.Serialize(requiredSize, serializeBuffer, objectIdProvider);
},
extraSize, std::forward<ExtraSizeSerializeFn>(SerializeExtraSize));
}
private:
template <typename Cmd, typename SerializeCmdFn, typename ExtraSizeSerializeFn>
void SerializeCommandImpl(const Cmd& cmd,
SerializeCmdFn&& SerializeCmd,
size_t extraSize,
ExtraSizeSerializeFn&& SerializeExtraSize) {
size_t commandSize = cmd.GetRequiredSize();
size_t requiredSize = commandSize + extraSize;
if (requiredSize <= mMaxAllocationSize) {
char* allocatedBuffer = static_cast<char*>(mSerializer->GetCmdSpace(requiredSize));
if (allocatedBuffer != nullptr) {
SerializeBuffer serializeBuffer(allocatedBuffer, requiredSize);
WireResult r1 = SerializeCmd(cmd, requiredSize, &serializeBuffer);
WireResult r2 = SerializeExtraSize(&serializeBuffer);
if (DAWN_UNLIKELY(r1 != WireResult::Success || r2 != WireResult::Success)) {
mSerializer->OnSerializeError();
}
}
return;
}
auto cmdSpace = std::unique_ptr<char[]>(AllocNoThrow<char>(requiredSize));
if (!cmdSpace) {
return;
}
SerializeBuffer serializeBuffer(cmdSpace.get(), requiredSize);
WireResult r1 = SerializeCmd(cmd, requiredSize, &serializeBuffer);
WireResult r2 = SerializeExtraSize(&serializeBuffer);
if (DAWN_UNLIKELY(r1 != WireResult::Success || r2 != WireResult::Success)) {
mSerializer->OnSerializeError();
return;
}
SerializeChunkedCommand(cmdSpace.get(), requiredSize);
}
void SerializeChunkedCommand(const char* allocatedBuffer, size_t remainingSize);
CommandSerializer* mSerializer;
size_t mMaxAllocationSize;
};
} // namespace dawn::wire
#endif // DAWNWIRE_CHUNKEDCOMMANDSERIALIZER_H_

View File

@@ -1,49 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/SupportedFeatures.h"
namespace dawn::wire {
// Note: Upon updating this list, please also update serialization/deserialization
// of limit structs on Adapter/Device initialization.
bool IsFeatureSupported(WGPUFeatureName feature) {
switch (feature) {
case WGPUFeatureName_Undefined:
case WGPUFeatureName_Force32:
case WGPUFeatureName_DawnNative:
return false;
case WGPUFeatureName_Depth24UnormStencil8:
case WGPUFeatureName_Depth32FloatStencil8:
case WGPUFeatureName_TimestampQuery:
case WGPUFeatureName_PipelineStatisticsQuery:
case WGPUFeatureName_TextureCompressionBC:
case WGPUFeatureName_TextureCompressionETC2:
case WGPUFeatureName_TextureCompressionASTC:
case WGPUFeatureName_IndirectFirstInstance:
case WGPUFeatureName_DepthClamping:
case WGPUFeatureName_DawnShaderFloat16:
case WGPUFeatureName_DawnInternalUsages:
case WGPUFeatureName_DawnMultiPlanarFormats:
return true;
}
// Catch-all, for unsupported features.
// "default:" is not used so we get compiler errors for
// newly added, unhandled features, but still catch completely
// unknown enums.
return false;
}
} // namespace dawn::wire

View File

@@ -1,26 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_SUPPORTEDFEATURES_H_
#define DAWNWIRE_SUPPORTEDFEATURES_H_
#include <dawn/webgpu.h>
namespace dawn::wire {
bool IsFeatureSupported(WGPUFeatureName feature);
} // namespace dawn::wire
#endif // DAWNWIRE_SUPPORTEDFEATURES_H_

View File

@@ -1,28 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/Wire.h"
namespace dawn::wire {
CommandSerializer::CommandSerializer() = default;
CommandSerializer::~CommandSerializer() = default;
void CommandSerializer::OnSerializeError() {
}
CommandHandler::CommandHandler() = default;
CommandHandler::~CommandHandler() = default;
} // namespace dawn::wire

View File

@@ -1,82 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/WireClient.h"
#include "dawn_wire/client/Client.h"
namespace dawn::wire {
WireClient::WireClient(const WireClientDescriptor& descriptor)
: mImpl(new client::Client(descriptor.serializer, descriptor.memoryTransferService)) {
}
WireClient::~WireClient() {
mImpl.reset();
}
const volatile char* WireClient::HandleCommands(const volatile char* commands, size_t size) {
return mImpl->HandleCommands(commands, size);
}
ReservedTexture WireClient::ReserveTexture(WGPUDevice device) {
return mImpl->ReserveTexture(device);
}
ReservedSwapChain WireClient::ReserveSwapChain(WGPUDevice device) {
return mImpl->ReserveSwapChain(device);
}
ReservedDevice WireClient::ReserveDevice() {
return mImpl->ReserveDevice();
}
ReservedInstance WireClient::ReserveInstance() {
return mImpl->ReserveInstance();
}
void WireClient::ReclaimTextureReservation(const ReservedTexture& reservation) {
mImpl->ReclaimTextureReservation(reservation);
}
void WireClient::ReclaimSwapChainReservation(const ReservedSwapChain& reservation) {
mImpl->ReclaimSwapChainReservation(reservation);
}
void WireClient::ReclaimDeviceReservation(const ReservedDevice& reservation) {
mImpl->ReclaimDeviceReservation(reservation);
}
void WireClient::ReclaimInstanceReservation(const ReservedInstance& reservation) {
mImpl->ReclaimInstanceReservation(reservation);
}
void WireClient::Disconnect() {
mImpl->Disconnect();
}
namespace client {
MemoryTransferService::MemoryTransferService() = default;
MemoryTransferService::~MemoryTransferService() = default;
MemoryTransferService::ReadHandle::ReadHandle() = default;
MemoryTransferService::ReadHandle::~ReadHandle() = default;
MemoryTransferService::WriteHandle::WriteHandle() = default;
MemoryTransferService::WriteHandle::~WriteHandle() = default;
} // namespace client
} // namespace dawn::wire

View File

@@ -1,60 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/WireDeserializeAllocator.h"
#include <algorithm>
namespace dawn::wire {
WireDeserializeAllocator::WireDeserializeAllocator() {
Reset();
}
WireDeserializeAllocator::~WireDeserializeAllocator() {
Reset();
}
void* WireDeserializeAllocator::GetSpace(size_t size) {
// Return space in the current buffer if possible first.
if (mRemainingSize >= size) {
char* buffer = mCurrentBuffer;
mCurrentBuffer += size;
mRemainingSize -= size;
return buffer;
}
// Otherwise allocate a new buffer and try again.
size_t allocationSize = std::max(size, size_t(2048));
char* allocation = static_cast<char*>(malloc(allocationSize));
if (allocation == nullptr) {
return nullptr;
}
mAllocations.push_back(allocation);
mCurrentBuffer = allocation;
mRemainingSize = allocationSize;
return GetSpace(size);
}
void WireDeserializeAllocator::Reset() {
for (auto allocation : mAllocations) {
free(allocation);
}
mAllocations.clear();
// The initial buffer is the inline buffer so that some allocations can be skipped
mCurrentBuffer = mStaticBuffer;
mRemainingSize = sizeof(mStaticBuffer);
}
} // namespace dawn::wire

View File

@@ -1,43 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_
#define DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_
#include "dawn_wire/WireCmd_autogen.h"
#include <vector>
namespace dawn::wire {
// A really really simple implementation of the DeserializeAllocator. It's main feature
// is that it has some inline storage so as to avoid allocations for the majority of
// commands.
class WireDeserializeAllocator : public DeserializeAllocator {
public:
WireDeserializeAllocator();
virtual ~WireDeserializeAllocator();
void* GetSpace(size_t size) override;
void Reset();
private:
size_t mRemainingSize = 0;
char* mCurrentBuffer = nullptr;
char mStaticBuffer[2048];
std::vector<char*> mAllocations;
};
} // namespace dawn::wire
#endif // DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_

View File

@@ -1,38 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_WIRERESULT_H_
#define DAWNWIRE_WIRERESULT_H_
#include "dawn/common/Compiler.h"
namespace dawn::wire {
enum class [[nodiscard]] WireResult{
Success,
FatalError,
};
// Macro to simplify error handling, similar to DAWN_TRY but for WireResult.
#define WIRE_TRY(EXPR) \
do { \
WireResult exprResult = EXPR; \
if (DAWN_UNLIKELY(exprResult != WireResult::Success)) { \
return exprResult; \
} \
} while (0)
} // namespace dawn::wire
#endif // DAWNWIRE_WIRERESULT_H_

View File

@@ -1,83 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/WireServer.h"
#include "dawn_wire/server/Server.h"
namespace dawn::wire {
WireServer::WireServer(const WireServerDescriptor& descriptor)
: mImpl(new server::Server(*descriptor.procs,
descriptor.serializer,
descriptor.memoryTransferService)) {
}
WireServer::~WireServer() {
mImpl.reset();
}
const volatile char* WireServer::HandleCommands(const volatile char* commands, size_t size) {
return mImpl->HandleCommands(commands, size);
}
bool WireServer::InjectTexture(WGPUTexture texture,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
return mImpl->InjectTexture(texture, id, generation, deviceId, deviceGeneration);
}
bool WireServer::InjectSwapChain(WGPUSwapChain swapchain,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
return mImpl->InjectSwapChain(swapchain, id, generation, deviceId, deviceGeneration);
}
bool WireServer::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) {
return mImpl->InjectDevice(device, id, generation);
}
bool WireServer::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) {
return mImpl->InjectInstance(instance, id, generation);
}
WGPUDevice WireServer::GetDevice(uint32_t id, uint32_t generation) {
return mImpl->GetDevice(id, generation);
}
namespace server {
MemoryTransferService::MemoryTransferService() = default;
MemoryTransferService::~MemoryTransferService() = default;
MemoryTransferService::ReadHandle::ReadHandle() = default;
MemoryTransferService::ReadHandle::~ReadHandle() = default;
MemoryTransferService::WriteHandle::WriteHandle() = default;
MemoryTransferService::WriteHandle::~WriteHandle() = default;
void MemoryTransferService::WriteHandle::SetTarget(void* data) {
mTargetData = data;
}
void MemoryTransferService::WriteHandle::SetDataLength(size_t dataLength) {
mDataLength = dataLength;
}
} // namespace server
} // namespace dawn::wire

View File

@@ -1,133 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Adapter.h"
#include "dawn/common/Log.h"
#include "dawn_wire/client/Client.h"
namespace dawn::wire::client {
Adapter::~Adapter() {
mRequestDeviceRequests.CloseAll([](RequestDeviceData* request) {
request->callback(WGPURequestDeviceStatus_Unknown, nullptr,
"Adapter destroyed before callback", request->userdata);
});
}
void Adapter::CancelCallbacksForDisconnect() {
mRequestDeviceRequests.CloseAll([](RequestDeviceData* request) {
request->callback(WGPURequestDeviceStatus_Unknown, nullptr, "GPU connection lost",
request->userdata);
});
}
bool Adapter::GetLimits(WGPUSupportedLimits* limits) const {
return mLimitsAndFeatures.GetLimits(limits);
}
bool Adapter::HasFeature(WGPUFeatureName feature) const {
return mLimitsAndFeatures.HasFeature(feature);
}
size_t Adapter::EnumerateFeatures(WGPUFeatureName* features) const {
return mLimitsAndFeatures.EnumerateFeatures(features);
}
void Adapter::SetLimits(const WGPUSupportedLimits* limits) {
return mLimitsAndFeatures.SetLimits(limits);
}
void Adapter::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
return mLimitsAndFeatures.SetFeatures(features, featuresCount);
}
void Adapter::SetProperties(const WGPUAdapterProperties* properties) {
mProperties = *properties;
mProperties.nextInChain = nullptr;
}
void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
*properties = mProperties;
}
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
callback(WGPURequestDeviceStatus_Error, nullptr, "GPU connection lost", userdata);
return;
}
auto* allocation = client->DeviceAllocator().New(client);
uint64_t serial = mRequestDeviceRequests.Add({callback, allocation->object->id, userdata});
AdapterRequestDeviceCmd cmd;
cmd.adapterId = this->id;
cmd.requestSerial = serial;
cmd.deviceObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
cmd.descriptor = descriptor;
client->SerializeCommand(cmd);
}
bool Client::DoAdapterRequestDeviceCallback(Adapter* adapter,
uint64_t requestSerial,
WGPURequestDeviceStatus status,
const char* message,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
// May have been deleted or recreated so this isn't an error.
if (adapter == nullptr) {
return true;
}
return adapter->OnRequestDeviceCallback(requestSerial, status, message, limits,
featuresCount, features);
}
bool Adapter::OnRequestDeviceCallback(uint64_t requestSerial,
WGPURequestDeviceStatus status,
const char* message,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
RequestDeviceData request;
if (!mRequestDeviceRequests.Acquire(requestSerial, &request)) {
return false;
}
Device* device = client->DeviceAllocator().GetObject(request.deviceObjectId);
// If the return status is a failure we should give a null device to the callback and
// free the allocation.
if (status != WGPURequestDeviceStatus_Success) {
client->DeviceAllocator().Free(device);
request.callback(status, nullptr, message, request.userdata);
return true;
}
device->SetLimits(limits);
device->SetFeatures(features, featuresCount);
request.callback(status, ToAPI(device), message, request.userdata);
return true;
}
WGPUDevice Adapter::CreateDevice(const WGPUDeviceDescriptor*) {
dawn::ErrorLog() << "adapter.CreateDevice not supported with dawn_wire.";
return nullptr;
}
} // namespace dawn::wire::client

View File

@@ -1,70 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_ADAPTER_H_
#define DAWNWIRE_CLIENT_ADAPTER_H_
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/LimitsAndFeatures.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
namespace dawn::wire::client {
class Adapter final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
~Adapter();
void CancelCallbacksForDisconnect() override;
bool GetLimits(WGPUSupportedLimits* limits) const;
bool HasFeature(WGPUFeatureName feature) const;
size_t EnumerateFeatures(WGPUFeatureName* features) const;
void SetLimits(const WGPUSupportedLimits* limits);
void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
void SetProperties(const WGPUAdapterProperties* properties);
void GetProperties(WGPUAdapterProperties* properties) const;
void RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata);
bool OnRequestDeviceCallback(uint64_t requestSerial,
WGPURequestDeviceStatus status,
const char* message,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features);
// Unimplementable. Only availale in dawn_native.
WGPUDevice CreateDevice(const WGPUDeviceDescriptor*);
private:
LimitsAndFeatures mLimitsAndFeatures;
WGPUAdapterProperties mProperties;
struct RequestDeviceData {
WGPURequestDeviceCallback callback = nullptr;
ObjectId deviceObjectId;
void* userdata = nullptr;
};
RequestTracker<RequestDeviceData> mRequestDeviceRequests;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_ADAPTER_H_

View File

@@ -1,29 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_APIOBJECTS_H_
#define DAWNWIRE_CLIENT_APIOBJECTS_H_
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/Adapter.h"
#include "dawn_wire/client/Buffer.h"
#include "dawn_wire/client/Device.h"
#include "dawn_wire/client/Instance.h"
#include "dawn_wire/client/Queue.h"
#include "dawn_wire/client/ShaderModule.h"
#include "dawn_wire/client/ApiObjects_autogen.h"
#endif // DAWNWIRE_CLIENT_APIOBJECTS_H_

View File

@@ -1,405 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Buffer.h"
#include "dawn_wire/BufferConsumer_impl.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h"
namespace dawn::wire::client {
// static
WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor) {
Client* wireClient = device->client;
bool mappable =
(descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 ||
descriptor->mappedAtCreation;
if (mappable && descriptor->size >= std::numeric_limits<size_t>::max()) {
device->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for map usage");
return device->CreateErrorBuffer();
}
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle = nullptr;
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
DeviceCreateBufferCmd cmd;
cmd.deviceId = device->id;
cmd.descriptor = descriptor;
cmd.readHandleCreateInfoLength = 0;
cmd.readHandleCreateInfo = nullptr;
cmd.writeHandleCreateInfoLength = 0;
cmd.writeHandleCreateInfo = nullptr;
if (mappable) {
if ((descriptor->usage & WGPUBufferUsage_MapRead) != 0) {
// Create the read handle on buffer creation.
readHandle.reset(
wireClient->GetMemoryTransferService()->CreateReadHandle(descriptor->size));
if (readHandle == nullptr) {
device->InjectError(WGPUErrorType_OutOfMemory,
"Failed to create buffer mapping");
return device->CreateErrorBuffer();
}
cmd.readHandleCreateInfoLength = readHandle->SerializeCreateSize();
}
if ((descriptor->usage & WGPUBufferUsage_MapWrite) != 0 ||
descriptor->mappedAtCreation) {
// Create the write handle on buffer creation.
writeHandle.reset(
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
if (writeHandle == nullptr) {
device->InjectError(WGPUErrorType_OutOfMemory,
"Failed to create buffer mapping");
return device->CreateErrorBuffer();
}
cmd.writeHandleCreateInfoLength = writeHandle->SerializeCreateSize();
}
}
// Create the buffer and send the creation command.
// This must happen after any potential device->CreateErrorBuffer()
// as server expects allocating ids to be monotonically increasing
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(wireClient);
Buffer* buffer = bufferObjectAndSerial->object.get();
buffer->mDevice = device;
buffer->mDeviceIsAlive = device->GetAliveWeakPtr();
buffer->mSize = descriptor->size;
buffer->mDestructWriteHandleOnUnmap = false;
if (descriptor->mappedAtCreation) {
// If the buffer is mapped at creation, a write handle is created and will be
// destructed on unmap if the buffer doesn't have MapWrite usage
// The buffer is mapped right now.
buffer->mMapState = MapState::MappedAtCreation;
// This flag is for write handle created by mappedAtCreation
// instead of MapWrite usage. We don't have such a case for read handle
buffer->mDestructWriteHandleOnUnmap =
(descriptor->usage & WGPUBufferUsage_MapWrite) == 0;
buffer->mMapOffset = 0;
buffer->mMapSize = buffer->mSize;
ASSERT(writeHandle != nullptr);
buffer->mMappedData = writeHandle->GetData();
}
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
wireClient->SerializeCommand(
cmd, cmd.readHandleCreateInfoLength + cmd.writeHandleCreateInfoLength,
[&](SerializeBuffer* serializeBuffer) {
if (readHandle != nullptr) {
char* readHandleBuffer;
WIRE_TRY(
serializeBuffer->NextN(cmd.readHandleCreateInfoLength, &readHandleBuffer));
// Serialize the ReadHandle into the space after the command.
readHandle->SerializeCreate(readHandleBuffer);
buffer->mReadHandle = std::move(readHandle);
}
if (writeHandle != nullptr) {
char* writeHandleBuffer;
WIRE_TRY(serializeBuffer->NextN(cmd.writeHandleCreateInfoLength,
&writeHandleBuffer));
// Serialize the WriteHandle into the space after the command.
writeHandle->SerializeCreate(writeHandleBuffer);
buffer->mWriteHandle = std::move(writeHandle);
}
return WireResult::Success;
});
return ToAPI(buffer);
}
// static
WGPUBuffer Buffer::CreateError(Device* device) {
auto* allocation = device->client->BufferAllocator().New(device->client);
allocation->object->mDevice = device;
allocation->object->mDeviceIsAlive = device->GetAliveWeakPtr();
DeviceCreateErrorBufferCmd cmd;
cmd.self = ToAPI(device);
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
device->client->SerializeCommand(cmd);
return ToAPI(allocation->object.get());
}
Buffer::~Buffer() {
ClearAllCallbacks(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
FreeMappedData();
}
void Buffer::CancelCallbacksForDisconnect() {
ClearAllCallbacks(WGPUBufferMapAsyncStatus_DeviceLost);
}
void Buffer::ClearAllCallbacks(WGPUBufferMapAsyncStatus status) {
mRequests.CloseAll([status](MapRequestData* request) {
if (request->callback != nullptr) {
request->callback(status, request->userdata);
}
});
}
void Buffer::MapAsync(WGPUMapModeFlags mode,
size_t offset,
size_t size,
WGPUBufferMapCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
return callback(WGPUBufferMapAsyncStatus_DeviceLost, userdata);
}
// Handle the defaulting of size required by WebGPU.
if ((size == WGPU_WHOLE_MAP_SIZE) && (offset <= mSize)) {
size = mSize - offset;
}
// Create the request structure that will hold information while this mapping is
// in flight.
MapRequestData request = {};
request.callback = callback;
request.userdata = userdata;
request.offset = offset;
request.size = size;
if (mode & WGPUMapMode_Read) {
request.type = MapRequestType::Read;
} else if (mode & WGPUMapMode_Write) {
request.type = MapRequestType::Write;
}
uint64_t serial = mRequests.Add(std::move(request));
// Serialize the command to send to the server.
BufferMapAsyncCmd cmd;
cmd.bufferId = this->id;
cmd.requestSerial = serial;
cmd.mode = mode;
cmd.offset = offset;
cmd.size = size;
client->SerializeCommand(cmd);
}
bool Buffer::OnMapAsyncCallback(uint64_t requestSerial,
uint32_t status,
uint64_t readDataUpdateInfoLength,
const uint8_t* readDataUpdateInfo) {
MapRequestData request;
if (!mRequests.Acquire(requestSerial, &request)) {
return false;
}
auto FailRequest = [&request]() -> bool {
if (request.callback != nullptr) {
request.callback(WGPUBufferMapAsyncStatus_DeviceLost, request.userdata);
}
return false;
};
// Take into account the client-side status of the request if the server says it is a success.
if (status == WGPUBufferMapAsyncStatus_Success) {
status = request.clientStatus;
}
if (status == WGPUBufferMapAsyncStatus_Success) {
switch (request.type) {
case MapRequestType::Read: {
if (readDataUpdateInfoLength > std::numeric_limits<size_t>::max()) {
// This is the size of data deserialized from the command stream, which must
// be CPU-addressable.
return FailRequest();
}
// Validate to prevent bad map request; buffer destroyed during map request
if (mReadHandle == nullptr) {
return FailRequest();
}
// Update user map data with server returned data
if (!mReadHandle->DeserializeDataUpdate(
readDataUpdateInfo, static_cast<size_t>(readDataUpdateInfoLength),
request.offset, request.size)) {
return FailRequest();
}
mMapState = MapState::MappedForRead;
mMappedData = const_cast<void*>(mReadHandle->GetData());
break;
}
case MapRequestType::Write: {
if (mWriteHandle == nullptr) {
return FailRequest();
}
mMapState = MapState::MappedForWrite;
mMappedData = mWriteHandle->GetData();
break;
}
default:
UNREACHABLE();
}
mMapOffset = request.offset;
mMapSize = request.size;
}
if (request.callback) {
request.callback(static_cast<WGPUBufferMapAsyncStatus>(status), request.userdata);
}
return true;
}
void* Buffer::GetMappedRange(size_t offset, size_t size) {
if (!IsMappedForWriting() || !CheckGetMappedRangeOffsetSize(offset, size)) {
return nullptr;
}
return static_cast<uint8_t*>(mMappedData) + offset;
}
const void* Buffer::GetConstMappedRange(size_t offset, size_t size) {
if (!(IsMappedForWriting() || IsMappedForReading()) ||
!CheckGetMappedRangeOffsetSize(offset, size)) {
return nullptr;
}
return static_cast<uint8_t*>(mMappedData) + offset;
}
void Buffer::Unmap() {
// Invalidate the local pointer, and cancel all other in-flight requests that would
// turn into errors anyway (you can't double map). This prevents race when the following
// happens, where the application code would have unmapped a buffer but still receive a
// callback:
// - Client -> Server: MapRequest1, Unmap, MapRequest2
// - Server -> Client: Result of MapRequest1
// - Unmap locally on the client
// - Server -> Client: Result of MapRequest2
// mWriteHandle can still be nullptr if buffer has been destroyed before unmap
if ((mMapState == MapState::MappedForWrite || mMapState == MapState::MappedAtCreation) &&
mWriteHandle != nullptr) {
// Writes need to be flushed before Unmap is sent. Unmap calls all associated
// in-flight callbacks which may read the updated data.
// Get the serialization size of data update writes.
size_t writeDataUpdateInfoLength =
mWriteHandle->SizeOfSerializeDataUpdate(mMapOffset, mMapSize);
BufferUpdateMappedDataCmd cmd;
cmd.bufferId = id;
cmd.writeDataUpdateInfoLength = writeDataUpdateInfoLength;
cmd.writeDataUpdateInfo = nullptr;
cmd.offset = mMapOffset;
cmd.size = mMapSize;
client->SerializeCommand(
cmd, writeDataUpdateInfoLength, [&](SerializeBuffer* serializeBuffer) {
char* writeHandleBuffer;
WIRE_TRY(serializeBuffer->NextN(writeDataUpdateInfoLength, &writeHandleBuffer));
// Serialize flush metadata into the space after the command.
// This closes the handle for writing.
mWriteHandle->SerializeDataUpdate(writeHandleBuffer, cmd.offset, cmd.size);
return WireResult::Success;
});
// If mDestructWriteHandleOnUnmap is true, that means the write handle is merely
// for mappedAtCreation usage. It is destroyed on unmap after flush to server
// instead of at buffer destruction.
if (mMapState == MapState::MappedAtCreation && mDestructWriteHandleOnUnmap) {
mWriteHandle = nullptr;
if (mReadHandle) {
// If it's both mappedAtCreation and MapRead we need to reset
// mMappedData to readHandle's GetData(). This could be changed to
// merging read/write handle in future
mMappedData = const_cast<void*>(mReadHandle->GetData());
}
}
}
// Free map access tokens
mMapState = MapState::Unmapped;
mMapOffset = 0;
mMapSize = 0;
// Tag all mapping requests still in flight as unmapped before callback.
mRequests.ForAll([](MapRequestData* request) {
if (request->clientStatus == WGPUBufferMapAsyncStatus_Success) {
request->clientStatus = WGPUBufferMapAsyncStatus_UnmappedBeforeCallback;
}
});
BufferUnmapCmd cmd;
cmd.self = ToAPI(this);
client->SerializeCommand(cmd);
}
void Buffer::Destroy() {
// Remove the current mapping and destroy Read/WriteHandles.
FreeMappedData();
// Tag all mapping requests still in flight as destroyed before callback.
mRequests.ForAll([](MapRequestData* request) {
if (request->clientStatus == WGPUBufferMapAsyncStatus_Success) {
request->clientStatus = WGPUBufferMapAsyncStatus_DestroyedBeforeCallback;
}
});
BufferDestroyCmd cmd;
cmd.self = ToAPI(this);
client->SerializeCommand(cmd);
}
bool Buffer::IsMappedForReading() const {
return mMapState == MapState::MappedForRead;
}
bool Buffer::IsMappedForWriting() const {
return mMapState == MapState::MappedForWrite || mMapState == MapState::MappedAtCreation;
}
bool Buffer::CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const {
if (offset % 8 != 0 || size % 4 != 0) {
return false;
}
if (size > mMapSize || offset < mMapOffset) {
return false;
}
size_t offsetInMappedRange = offset - mMapOffset;
return offsetInMappedRange <= mMapSize - size;
}
void Buffer::FreeMappedData() {
#if defined(DAWN_ENABLE_ASSERTS)
// When in "debug" mode, 0xCA-out the mapped data when we free it so that in we can detect
// use-after-free of the mapped data. This is particularly useful for WebGPU test about the
// interaction of mapping and GC.
if (mMappedData) {
memset(static_cast<uint8_t*>(mMappedData) + mMapOffset, 0xCA, mMapSize);
}
#endif // defined(DAWN_ENABLE_ASSERTS)
mMapOffset = 0;
mMapSize = 0;
mReadHandle = nullptr;
mWriteHandle = nullptr;
mMappedData = nullptr;
}
} // namespace dawn::wire::client

View File

@@ -1,109 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_BUFFER_H_
#define DAWNWIRE_CLIENT_BUFFER_H_
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
namespace dawn::wire::client {
class Device;
class Buffer final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor);
static WGPUBuffer CreateError(Device* device);
~Buffer();
bool OnMapAsyncCallback(uint64_t requestSerial,
uint32_t status,
uint64_t readDataUpdateInfoLength,
const uint8_t* readDataUpdateInfo);
void MapAsync(WGPUMapModeFlags mode,
size_t offset,
size_t size,
WGPUBufferMapCallback callback,
void* userdata);
void* GetMappedRange(size_t offset, size_t size);
const void* GetConstMappedRange(size_t offset, size_t size);
void Unmap();
void Destroy();
private:
void CancelCallbacksForDisconnect() override;
void ClearAllCallbacks(WGPUBufferMapAsyncStatus status);
bool IsMappedForReading() const;
bool IsMappedForWriting() const;
bool CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const;
void FreeMappedData();
Device* mDevice;
enum class MapRequestType { None, Read, Write };
enum class MapState {
Unmapped,
MappedForRead,
MappedForWrite,
MappedAtCreation,
};
// We want to defer all the validation to the server, which means we could have multiple
// map request in flight at a single time and need to track them separately.
// On well-behaved applications, only one request should exist at a single time.
struct MapRequestData {
WGPUBufferMapCallback callback = nullptr;
void* userdata = nullptr;
size_t offset = 0;
size_t size = 0;
// When the buffer is destroyed or unmapped too early, the unmappedBeforeX status takes
// precedence over the success value returned from the server. However Error statuses
// from the server take precedence over the client-side status.
WGPUBufferMapAsyncStatus clientStatus = WGPUBufferMapAsyncStatus_Success;
MapRequestType type = MapRequestType::None;
};
RequestTracker<MapRequestData> mRequests;
uint64_t mSize = 0;
// Only one mapped pointer can be active at a time because Unmap clears all the in-flight
// requests.
// TODO(enga): Use a tagged pointer to save space.
std::unique_ptr<MemoryTransferService::ReadHandle> mReadHandle = nullptr;
std::unique_ptr<MemoryTransferService::WriteHandle> mWriteHandle = nullptr;
MapState mMapState = MapState::Unmapped;
bool mDestructWriteHandleOnUnmap = false;
void* mMappedData = nullptr;
size_t mMapOffset = 0;
size_t mMapSize = 0;
std::weak_ptr<bool> mDeviceIsAlive;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_BUFFER_H_

View File

@@ -1,171 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Client.h"
#include "dawn/common/Compiler.h"
#include "dawn_wire/client/Device.h"
namespace dawn::wire::client {
namespace {
class NoopCommandSerializer final : public CommandSerializer {
public:
static NoopCommandSerializer* GetInstance() {
static NoopCommandSerializer gNoopCommandSerializer;
return &gNoopCommandSerializer;
}
~NoopCommandSerializer() = default;
size_t GetMaximumAllocationSize() const final {
return 0;
}
void* GetCmdSpace(size_t size) final {
return nullptr;
}
bool Flush() final {
return false;
}
};
} // anonymous namespace
Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService)
: ClientBase(), mSerializer(serializer), mMemoryTransferService(memoryTransferService) {
if (mMemoryTransferService == nullptr) {
// If a MemoryTransferService is not provided, fall back to inline memory.
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
mMemoryTransferService = mOwnedMemoryTransferService.get();
}
}
Client::~Client() {
DestroyAllObjects();
}
void Client::DestroyAllObjects() {
for (auto& objectList : mObjects) {
ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
if (objectType == ObjectType::Device) {
continue;
}
while (!objectList.empty()) {
ObjectBase* object = objectList.head()->value();
DestroyObjectCmd cmd;
cmd.objectType = objectType;
cmd.objectId = object->id;
SerializeCommand(cmd);
FreeObject(objectType, object);
}
}
while (!mObjects[ObjectType::Device].empty()) {
ObjectBase* object = mObjects[ObjectType::Device].head()->value();
DestroyObjectCmd cmd;
cmd.objectType = ObjectType::Device;
cmd.objectId = object->id;
SerializeCommand(cmd);
FreeObject(ObjectType::Device, object);
}
}
ReservedTexture Client::ReserveTexture(WGPUDevice device) {
auto* allocation = TextureAllocator().New(this);
ReservedTexture result;
result.texture = ToAPI(allocation->object.get());
result.id = allocation->object->id;
result.generation = allocation->generation;
result.deviceId = FromAPI(device)->id;
result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
return result;
}
ReservedSwapChain Client::ReserveSwapChain(WGPUDevice device) {
auto* allocation = SwapChainAllocator().New(this);
ReservedSwapChain result;
result.swapchain = ToAPI(allocation->object.get());
result.id = allocation->object->id;
result.generation = allocation->generation;
result.deviceId = FromAPI(device)->id;
result.deviceGeneration = DeviceAllocator().GetGeneration(FromAPI(device)->id);
return result;
}
ReservedDevice Client::ReserveDevice() {
auto* allocation = DeviceAllocator().New(this);
ReservedDevice result;
result.device = ToAPI(allocation->object.get());
result.id = allocation->object->id;
result.generation = allocation->generation;
return result;
}
ReservedInstance Client::ReserveInstance() {
auto* allocation = InstanceAllocator().New(this);
ReservedInstance result;
result.instance = ToAPI(allocation->object.get());
result.id = allocation->object->id;
result.generation = allocation->generation;
return result;
}
void Client::ReclaimTextureReservation(const ReservedTexture& reservation) {
TextureAllocator().Free(FromAPI(reservation.texture));
}
void Client::ReclaimSwapChainReservation(const ReservedSwapChain& reservation) {
SwapChainAllocator().Free(FromAPI(reservation.swapchain));
}
void Client::ReclaimDeviceReservation(const ReservedDevice& reservation) {
DeviceAllocator().Free(FromAPI(reservation.device));
}
void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) {
InstanceAllocator().Free(FromAPI(reservation.instance));
}
void Client::Disconnect() {
mDisconnected = true;
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
auto& deviceList = mObjects[ObjectType::Device];
{
for (LinkNode<ObjectBase>* device = deviceList.head(); device != deviceList.end();
device = device->next()) {
static_cast<Device*>(device->value())
->HandleDeviceLost(WGPUDeviceLostReason_Undefined, "GPU connection lost");
}
}
for (auto& objectList : mObjects) {
for (LinkNode<ObjectBase>* object = objectList.head(); object != objectList.end();
object = object->next()) {
object->value()->CancelCallbacksForDisconnect();
}
}
}
bool Client::IsDisconnected() const {
return mDisconnected;
}
} // namespace dawn::wire::client

View File

@@ -1,95 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_CLIENT_H_
#define DAWNWIRE_CLIENT_CLIENT_H_
#include <dawn/webgpu.h>
#include <dawn_wire/Wire.h>
#include "dawn/common/LinkedList.h"
#include "dawn/common/NonCopyable.h"
#include "dawn_wire/ChunkedCommandSerializer.h"
#include "dawn_wire/WireClient.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/WireDeserializeAllocator.h"
#include "dawn_wire/client/ClientBase_autogen.h"
namespace dawn::wire::client {
class Device;
class MemoryTransferService;
class Client : public ClientBase {
public:
Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService);
~Client() override;
// ChunkedCommandHandler implementation
const volatile char* HandleCommandsImpl(const volatile char* commands,
size_t size) override;
MemoryTransferService* GetMemoryTransferService() const {
return mMemoryTransferService;
}
ReservedTexture ReserveTexture(WGPUDevice device);
ReservedSwapChain ReserveSwapChain(WGPUDevice device);
ReservedDevice ReserveDevice();
ReservedInstance ReserveInstance();
void ReclaimTextureReservation(const ReservedTexture& reservation);
void ReclaimSwapChainReservation(const ReservedSwapChain& reservation);
void ReclaimDeviceReservation(const ReservedDevice& reservation);
void ReclaimInstanceReservation(const ReservedInstance& reservation);
template <typename Cmd>
void SerializeCommand(const Cmd& cmd) {
mSerializer.SerializeCommand(cmd, *this);
}
template <typename Cmd, typename ExtraSizeSerializeFn>
void SerializeCommand(const Cmd& cmd,
size_t extraSize,
ExtraSizeSerializeFn&& SerializeExtraSize) {
mSerializer.SerializeCommand(cmd, *this, extraSize, SerializeExtraSize);
}
void Disconnect();
bool IsDisconnected() const;
template <typename T>
void TrackObject(T* object) {
mObjects[ObjectTypeToTypeEnum<T>::value].Append(object);
}
private:
void DestroyAllObjects();
#include "dawn_wire/client/ClientPrototypes_autogen.inc"
ChunkedCommandSerializer mSerializer;
WireDeserializeAllocator mAllocator;
MemoryTransferService* mMemoryTransferService = nullptr;
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
PerObjectType<LinkedList<ObjectBase>> mObjects;
bool mDisconnected = false;
};
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_CLIENT_H_

View File

@@ -1,133 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Assert.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h"
#include <limits>
namespace dawn::wire::client {
bool Client::DoDeviceUncapturedErrorCallback(Device* device,
WGPUErrorType errorType,
const char* message) {
switch (errorType) {
case WGPUErrorType_NoError:
case WGPUErrorType_Validation:
case WGPUErrorType_OutOfMemory:
case WGPUErrorType_Unknown:
case WGPUErrorType_DeviceLost:
break;
default:
return false;
}
if (device == nullptr) {
// The device might have been deleted or recreated so this isn't an error.
return true;
}
device->HandleError(errorType, message);
return true;
}
bool Client::DoDeviceLoggingCallback(Device* device,
WGPULoggingType loggingType,
const char* message) {
if (device == nullptr) {
// The device might have been deleted or recreated so this isn't an error.
return true;
}
device->HandleLogging(loggingType, message);
return true;
}
bool Client::DoDeviceLostCallback(Device* device,
WGPUDeviceLostReason reason,
char const* message) {
if (device == nullptr) {
// The device might have been deleted or recreated so this isn't an error.
return true;
}
device->HandleDeviceLost(reason, message);
return true;
}
bool Client::DoDevicePopErrorScopeCallback(Device* device,
uint64_t requestSerial,
WGPUErrorType errorType,
const char* message) {
if (device == nullptr) {
// The device might have been deleted or recreated so this isn't an error.
return true;
}
return device->OnPopErrorScopeCallback(requestSerial, errorType, message);
}
bool Client::DoBufferMapAsyncCallback(Buffer* buffer,
uint64_t requestSerial,
uint32_t status,
uint64_t readDataUpdateInfoLength,
const uint8_t* readDataUpdateInfo) {
// The buffer might have been deleted or recreated so this isn't an error.
if (buffer == nullptr) {
return true;
}
return buffer->OnMapAsyncCallback(requestSerial, status, readDataUpdateInfoLength,
readDataUpdateInfo);
}
bool Client::DoQueueWorkDoneCallback(Queue* queue,
uint64_t requestSerial,
WGPUQueueWorkDoneStatus status) {
// The queue might have been deleted or recreated so this isn't an error.
if (queue == nullptr) {
return true;
}
return queue->OnWorkDoneCallback(requestSerial, status);
}
bool Client::DoDeviceCreateComputePipelineAsyncCallback(Device* device,
uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message) {
// The device might have been deleted or recreated so this isn't an error.
if (device == nullptr) {
return true;
}
return device->OnCreateComputePipelineAsyncCallback(requestSerial, status, message);
}
bool Client::DoDeviceCreateRenderPipelineAsyncCallback(Device* device,
uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message) {
// The device might have been deleted or recreated so this isn't an error.
if (device == nullptr) {
return true;
}
return device->OnCreateRenderPipelineAsyncCallback(requestSerial, status, message);
}
bool Client::DoShaderModuleGetCompilationInfoCallback(ShaderModule* shaderModule,
uint64_t requestSerial,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info) {
// The shader module might have been deleted or recreated so this isn't an error.
if (shaderModule == nullptr) {
return true;
}
return shaderModule->GetCompilationInfoCallback(requestSerial, status, info);
}
} // namespace dawn::wire::client

View File

@@ -1,131 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Alloc.h"
#include "dawn/common/Assert.h"
#include "dawn_wire/WireClient.h"
#include "dawn_wire/client/Client.h"
#include <cstring>
namespace dawn::wire::client {
class InlineMemoryTransferService : public MemoryTransferService {
class ReadHandleImpl : public ReadHandle {
public:
explicit ReadHandleImpl(std::unique_ptr<uint8_t[]> stagingData, size_t size)
: mStagingData(std::move(stagingData)), mSize(size) {
}
~ReadHandleImpl() override = default;
size_t SerializeCreateSize() override {
return 0;
}
void SerializeCreate(void*) override {
}
const void* GetData() override {
return mStagingData.get();
}
bool DeserializeDataUpdate(const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) override {
if (deserializeSize != size || deserializePointer == nullptr) {
return false;
}
if (offset > mSize || size > mSize - offset) {
return false;
}
void* start = static_cast<uint8_t*>(mStagingData.get()) + offset;
memcpy(start, deserializePointer, size);
return true;
}
private:
std::unique_ptr<uint8_t[]> mStagingData;
size_t mSize;
};
class WriteHandleImpl : public WriteHandle {
public:
explicit WriteHandleImpl(std::unique_ptr<uint8_t[]> stagingData, size_t size)
: mStagingData(std::move(stagingData)), mSize(size) {
}
~WriteHandleImpl() override = default;
size_t SerializeCreateSize() override {
return 0;
}
void SerializeCreate(void*) override {
}
void* GetData() override {
return mStagingData.get();
}
size_t SizeOfSerializeDataUpdate(size_t offset, size_t size) override {
ASSERT(offset <= mSize);
ASSERT(size <= mSize - offset);
return size;
}
void SerializeDataUpdate(void* serializePointer, size_t offset, size_t size) override {
ASSERT(mStagingData != nullptr);
ASSERT(serializePointer != nullptr);
ASSERT(offset <= mSize);
ASSERT(size <= mSize - offset);
memcpy(serializePointer, static_cast<uint8_t*>(mStagingData.get()) + offset, size);
}
private:
std::unique_ptr<uint8_t[]> mStagingData;
size_t mSize;
};
public:
InlineMemoryTransferService() {
}
~InlineMemoryTransferService() override = default;
ReadHandle* CreateReadHandle(size_t size) override {
auto stagingData = std::unique_ptr<uint8_t[]>(AllocNoThrow<uint8_t>(size));
if (stagingData) {
return new ReadHandleImpl(std::move(stagingData), size);
}
return nullptr;
}
WriteHandle* CreateWriteHandle(size_t size) override {
auto stagingData = std::unique_ptr<uint8_t[]>(AllocNoThrow<uint8_t>(size));
if (stagingData) {
memset(stagingData.get(), 0, size);
return new WriteHandleImpl(std::move(stagingData), size);
}
return nullptr;
}
};
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService() {
return std::make_unique<InlineMemoryTransferService>();
}
} // namespace dawn::wire::client

View File

@@ -1,105 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/ClientMemoryTransferService_mock.h"
#include <cstdio>
#include "dawn/common/Assert.h"
namespace dawn::wire::client {
MockMemoryTransferService::MockReadHandle::MockReadHandle(MockMemoryTransferService* service)
: ReadHandle(), mService(service) {
}
MockMemoryTransferService::MockReadHandle::~MockReadHandle() {
mService->OnReadHandleDestroy(this);
}
size_t MockMemoryTransferService::MockReadHandle::SerializeCreateSize() {
return mService->OnReadHandleSerializeCreateSize(this);
}
void MockMemoryTransferService::MockReadHandle::SerializeCreate(void* serializePointer) {
mService->OnReadHandleSerializeCreate(this, serializePointer);
}
const void* MockMemoryTransferService::MockReadHandle::GetData() {
return mService->OnReadHandleGetData(this);
}
bool MockMemoryTransferService::MockReadHandle::DeserializeDataUpdate(
const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) {
ASSERT(deserializeSize % sizeof(uint32_t) == 0);
return mService->OnReadHandleDeserializeDataUpdate(
this, reinterpret_cast<const uint32_t*>(deserializePointer), deserializeSize, offset,
size);
}
MockMemoryTransferService::MockWriteHandle::MockWriteHandle(MockMemoryTransferService* service)
: WriteHandle(), mService(service) {
}
MockMemoryTransferService::MockWriteHandle::~MockWriteHandle() {
mService->OnWriteHandleDestroy(this);
}
size_t MockMemoryTransferService::MockWriteHandle::SerializeCreateSize() {
return mService->OnWriteHandleSerializeCreateSize(this);
}
void MockMemoryTransferService::MockWriteHandle::SerializeCreate(void* serializePointer) {
mService->OnWriteHandleSerializeCreate(this, serializePointer);
}
void* MockMemoryTransferService::MockWriteHandle::GetData() {
return mService->OnWriteHandleGetData(this);
}
size_t MockMemoryTransferService::MockWriteHandle::SizeOfSerializeDataUpdate(size_t offset,
size_t size) {
return mService->OnWriteHandleSizeOfSerializeDataUpdate(this, offset, size);
}
void MockMemoryTransferService::MockWriteHandle::SerializeDataUpdate(void* serializePointer,
size_t offset,
size_t size) {
mService->OnWriteHandleSerializeDataUpdate(this, serializePointer, offset, size);
}
MockMemoryTransferService::MockMemoryTransferService() = default;
MockMemoryTransferService::~MockMemoryTransferService() = default;
MockMemoryTransferService::ReadHandle* MockMemoryTransferService::CreateReadHandle(
size_t size) {
return OnCreateReadHandle(size);
}
MockMemoryTransferService::WriteHandle* MockMemoryTransferService::CreateWriteHandle(
size_t size) {
return OnCreateWriteHandle(size);
}
MockMemoryTransferService::MockReadHandle* MockMemoryTransferService::NewReadHandle() {
return new MockReadHandle(this);
}
MockMemoryTransferService::MockWriteHandle* MockMemoryTransferService::NewWriteHandle() {
return new MockWriteHandle(this);
}
} // namespace dawn::wire::client

View File

@@ -1,99 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_
#define DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_
#include <gmock/gmock.h>
#include "dawn_wire/WireClient.h"
#include "dawn_wire/client/Client.h"
namespace dawn::wire::client {
class MockMemoryTransferService : public MemoryTransferService {
public:
class MockReadHandle : public ReadHandle {
public:
explicit MockReadHandle(MockMemoryTransferService* service);
~MockReadHandle() override;
size_t SerializeCreateSize() override;
void SerializeCreate(void* serializePointer) override;
const void* GetData() override;
bool DeserializeDataUpdate(const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) override;
private:
MockMemoryTransferService* mService;
};
class MockWriteHandle : public WriteHandle {
public:
explicit MockWriteHandle(MockMemoryTransferService* service);
~MockWriteHandle() override;
size_t SerializeCreateSize() override;
void SerializeCreate(void* serializePointer) override;
void* GetData() override;
size_t SizeOfSerializeDataUpdate(size_t offset, size_t size) override;
void SerializeDataUpdate(void* serializePointer, size_t offset, size_t size) override;
private:
MockMemoryTransferService* mService;
};
MockMemoryTransferService();
~MockMemoryTransferService() override;
ReadHandle* CreateReadHandle(size_t) override;
WriteHandle* CreateWriteHandle(size_t) override;
MockReadHandle* NewReadHandle();
MockWriteHandle* NewWriteHandle();
MOCK_METHOD(ReadHandle*, OnCreateReadHandle, (size_t));
MOCK_METHOD(WriteHandle*, OnCreateWriteHandle, (size_t));
MOCK_METHOD(size_t, OnReadHandleSerializeCreateSize, (const ReadHandle*));
MOCK_METHOD(void, OnReadHandleSerializeCreate, (const ReadHandle*, void* serializePointer));
MOCK_METHOD((const void*), OnReadHandleGetData, (const ReadHandle*));
MOCK_METHOD(bool,
OnReadHandleDeserializeDataUpdate,
(const ReadHandle*,
const uint32_t* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size));
MOCK_METHOD(void, OnReadHandleDestroy, (const ReadHandle*));
MOCK_METHOD(size_t, OnWriteHandleSerializeCreateSize, (const void* WriteHandle));
MOCK_METHOD(void,
OnWriteHandleSerializeCreate,
(const void* WriteHandle, void* serializePointer));
MOCK_METHOD((void*), OnWriteHandleGetData, (const void* WriteHandle));
MOCK_METHOD(size_t,
OnWriteHandleSizeOfSerializeDataUpdate,
(const void* WriteHandle, size_t offset, size_t size));
MOCK_METHOD(size_t,
OnWriteHandleSerializeDataUpdate,
(const void* WriteHandle, void* serializePointer, size_t offset, size_t size));
MOCK_METHOD(void, OnWriteHandleDestroy, (const void* WriteHandle));
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_

View File

@@ -1,342 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Device.h"
#include "dawn/common/Assert.h"
#include "dawn/common/Log.h"
#include "dawn_wire/client/ApiObjects_autogen.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/ObjectAllocator.h"
namespace dawn::wire::client {
Device::Device(Client* clientIn, uint32_t initialRefcount, uint32_t initialId)
: ObjectBase(clientIn, initialRefcount, initialId), mIsAlive(std::make_shared<bool>()) {
#if defined(DAWN_ENABLE_ASSERTS)
mErrorCallback = [](WGPUErrorType, char const*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
dawn::WarningLog() << "No Dawn device uncaptured error callback was set. This is "
"probably not intended. If you really want to ignore errors "
"and suppress this message, set the callback to null.";
}
};
mDeviceLostCallback = [](WGPUDeviceLostReason, char const*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
dawn::WarningLog() << "No Dawn device lost callback was set. This is probably not "
"intended. If you really want to ignore device lost "
"and suppress this message, set the callback to null.";
}
};
#endif // DAWN_ENABLE_ASSERTS
}
Device::~Device() {
mErrorScopes.CloseAll([](ErrorScopeData* request) {
request->callback(WGPUErrorType_Unknown, "Device destroyed before callback",
request->userdata);
});
mCreatePipelineAsyncRequests.CloseAll([](CreatePipelineAsyncRequest* request) {
if (request->createComputePipelineAsyncCallback != nullptr) {
request->createComputePipelineAsyncCallback(
WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
"Device destroyed before callback", request->userdata);
} else {
ASSERT(request->createRenderPipelineAsyncCallback != nullptr);
request->createRenderPipelineAsyncCallback(
WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
"Device destroyed before callback", request->userdata);
}
});
}
bool Device::GetLimits(WGPUSupportedLimits* limits) const {
return mLimitsAndFeatures.GetLimits(limits);
}
bool Device::HasFeature(WGPUFeatureName feature) const {
return mLimitsAndFeatures.HasFeature(feature);
}
size_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
return mLimitsAndFeatures.EnumerateFeatures(features);
}
void Device::SetLimits(const WGPUSupportedLimits* limits) {
return mLimitsAndFeatures.SetLimits(limits);
}
void Device::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
return mLimitsAndFeatures.SetFeatures(features, featuresCount);
}
void Device::HandleError(WGPUErrorType errorType, const char* message) {
if (mErrorCallback) {
mErrorCallback(errorType, message, mErrorUserdata);
}
}
void Device::HandleLogging(WGPULoggingType loggingType, const char* message) {
if (mLoggingCallback) {
// Since client always run in single thread, calling the callback directly is safe.
mLoggingCallback(loggingType, message, mLoggingUserdata);
}
}
void Device::HandleDeviceLost(WGPUDeviceLostReason reason, const char* message) {
if (mDeviceLostCallback && !mDidRunLostCallback) {
mDidRunLostCallback = true;
mDeviceLostCallback(reason, message, mDeviceLostUserdata);
}
}
void Device::CancelCallbacksForDisconnect() {
mErrorScopes.CloseAll([](ErrorScopeData* request) {
request->callback(WGPUErrorType_DeviceLost, "Device lost", request->userdata);
});
mCreatePipelineAsyncRequests.CloseAll([](CreatePipelineAsyncRequest* request) {
if (request->createComputePipelineAsyncCallback != nullptr) {
request->createComputePipelineAsyncCallback(
WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr, "Device lost",
request->userdata);
} else {
ASSERT(request->createRenderPipelineAsyncCallback != nullptr);
request->createRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost,
nullptr, "Device lost",
request->userdata);
}
});
}
std::weak_ptr<bool> Device::GetAliveWeakPtr() {
return mIsAlive;
}
void Device::SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata) {
mErrorCallback = errorCallback;
mErrorUserdata = errorUserdata;
}
void Device::SetLoggingCallback(WGPULoggingCallback callback, void* userdata) {
mLoggingCallback = callback;
mLoggingUserdata = userdata;
}
void Device::SetDeviceLostCallback(WGPUDeviceLostCallback callback, void* userdata) {
mDeviceLostCallback = callback;
mDeviceLostUserdata = userdata;
}
void Device::PushErrorScope(WGPUErrorFilter filter) {
mErrorScopeStackSize++;
DevicePushErrorScopeCmd cmd;
cmd.self = ToAPI(this);
cmd.filter = filter;
client->SerializeCommand(cmd);
}
bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
if (mErrorScopeStackSize == 0) {
return false;
}
mErrorScopeStackSize--;
if (client->IsDisconnected()) {
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
return true;
}
uint64_t serial = mErrorScopes.Add({callback, userdata});
DevicePopErrorScopeCmd cmd;
cmd.deviceId = this->id;
cmd.requestSerial = serial;
client->SerializeCommand(cmd);
return true;
}
bool Device::OnPopErrorScopeCallback(uint64_t requestSerial,
WGPUErrorType type,
const char* message) {
switch (type) {
case WGPUErrorType_NoError:
case WGPUErrorType_Validation:
case WGPUErrorType_OutOfMemory:
case WGPUErrorType_Unknown:
case WGPUErrorType_DeviceLost:
break;
default:
return false;
}
ErrorScopeData request;
if (!mErrorScopes.Acquire(requestSerial, &request)) {
return false;
}
request.callback(type, message, request.userdata);
return true;
}
void Device::InjectError(WGPUErrorType type, const char* message) {
DeviceInjectErrorCmd cmd;
cmd.self = ToAPI(this);
cmd.type = type;
cmd.message = message;
client->SerializeCommand(cmd);
}
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
return Buffer::Create(this, descriptor);
}
WGPUBuffer Device::CreateErrorBuffer() {
return Buffer::CreateError(this);
}
WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until
// it has been injected on the Server. It cannot happen immediately
// on construction.
if (mQueue == nullptr) {
// Get the primary queue for this device.
auto* allocation = client->QueueAllocator().New(client);
mQueue = allocation->object.get();
DeviceGetQueueCmd cmd;
cmd.self = ToAPI(this);
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
client->SerializeCommand(cmd);
}
mQueue->refcount++;
return ToAPI(mQueue);
}
void Device::CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"GPU device disconnected", userdata);
}
auto* allocation = client->ComputePipelineAllocator().New(client);
CreatePipelineAsyncRequest request = {};
request.createComputePipelineAsyncCallback = callback;
request.userdata = userdata;
request.pipelineObjectID = allocation->object->id;
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
DeviceCreateComputePipelineAsyncCmd cmd;
cmd.deviceId = this->id;
cmd.descriptor = descriptor;
cmd.requestSerial = serial;
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
client->SerializeCommand(cmd);
}
bool Device::OnCreateComputePipelineAsyncCallback(uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message) {
CreatePipelineAsyncRequest request;
if (!mCreatePipelineAsyncRequests.Acquire(requestSerial, &request)) {
return false;
}
auto pipelineAllocation =
client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
client->ComputePipelineAllocator().Free(pipelineAllocation);
request.createComputePipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
WGPUComputePipeline pipeline = reinterpret_cast<WGPUComputePipeline>(pipelineAllocation);
request.createComputePipelineAsyncCallback(status, pipeline, message, request.userdata);
return true;
}
void Device::CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
return callback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"GPU device disconnected", userdata);
}
auto* allocation = client->RenderPipelineAllocator().New(client);
CreatePipelineAsyncRequest request = {};
request.createRenderPipelineAsyncCallback = callback;
request.userdata = userdata;
request.pipelineObjectID = allocation->object->id;
uint64_t serial = mCreatePipelineAsyncRequests.Add(std::move(request));
DeviceCreateRenderPipelineAsyncCmd cmd;
cmd.deviceId = this->id;
cmd.descriptor = descriptor;
cmd.requestSerial = serial;
cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
client->SerializeCommand(cmd);
}
bool Device::OnCreateRenderPipelineAsyncCallback(uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message) {
CreatePipelineAsyncRequest request;
if (!mCreatePipelineAsyncRequests.Acquire(requestSerial, &request)) {
return false;
}
auto pipelineAllocation =
client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
// free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
client->RenderPipelineAllocator().Free(pipelineAllocation);
request.createRenderPipelineAsyncCallback(status, nullptr, message, request.userdata);
return true;
}
WGPURenderPipeline pipeline = reinterpret_cast<WGPURenderPipeline>(pipelineAllocation);
request.createRenderPipelineAsyncCallback(status, pipeline, message, request.userdata);
return true;
}
} // namespace dawn::wire::client

View File

@@ -1,112 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_DEVICE_H_
#define DAWNWIRE_CLIENT_DEVICE_H_
#include <dawn/webgpu.h>
#include "dawn/common/LinkedList.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ApiObjects_autogen.h"
#include "dawn_wire/client/LimitsAndFeatures.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
#include <memory>
namespace dawn::wire::client {
class Client;
class Queue;
class Device final : public ObjectBase {
public:
Device(Client* client, uint32_t refcount, uint32_t id);
~Device();
void SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata);
void SetLoggingCallback(WGPULoggingCallback errorCallback, void* errorUserdata);
void SetDeviceLostCallback(WGPUDeviceLostCallback errorCallback, void* errorUserdata);
void InjectError(WGPUErrorType type, const char* message);
void PushErrorScope(WGPUErrorFilter filter);
bool PopErrorScope(WGPUErrorCallback callback, void* userdata);
WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
WGPUBuffer CreateErrorBuffer();
WGPUComputePipeline CreateComputePipeline(WGPUComputePipelineDescriptor const* descriptor);
void CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata);
void CreateRenderPipelineAsync(WGPURenderPipelineDescriptor const* descriptor,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata);
void HandleError(WGPUErrorType errorType, const char* message);
void HandleLogging(WGPULoggingType loggingType, const char* message);
void HandleDeviceLost(WGPUDeviceLostReason reason, const char* message);
bool OnPopErrorScopeCallback(uint64_t requestSerial,
WGPUErrorType type,
const char* message);
bool OnCreateComputePipelineAsyncCallback(uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message);
bool OnCreateRenderPipelineAsyncCallback(uint64_t requestSerial,
WGPUCreatePipelineAsyncStatus status,
const char* message);
bool GetLimits(WGPUSupportedLimits* limits) const;
bool HasFeature(WGPUFeatureName feature) const;
size_t EnumerateFeatures(WGPUFeatureName* features) const;
void SetLimits(const WGPUSupportedLimits* limits);
void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
WGPUQueue GetQueue();
void CancelCallbacksForDisconnect() override;
std::weak_ptr<bool> GetAliveWeakPtr();
private:
LimitsAndFeatures mLimitsAndFeatures;
struct ErrorScopeData {
WGPUErrorCallback callback = nullptr;
void* userdata = nullptr;
};
RequestTracker<ErrorScopeData> mErrorScopes;
uint64_t mErrorScopeStackSize = 0;
struct CreatePipelineAsyncRequest {
WGPUCreateComputePipelineAsyncCallback createComputePipelineAsyncCallback = nullptr;
WGPUCreateRenderPipelineAsyncCallback createRenderPipelineAsyncCallback = nullptr;
void* userdata = nullptr;
ObjectId pipelineObjectID;
};
RequestTracker<CreatePipelineAsyncRequest> mCreatePipelineAsyncRequests;
WGPUErrorCallback mErrorCallback = nullptr;
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
WGPULoggingCallback mLoggingCallback = nullptr;
bool mDidRunLostCallback = false;
void* mErrorUserdata = nullptr;
void* mDeviceLostUserdata = nullptr;
void* mLoggingUserdata = nullptr;
Queue* mQueue = nullptr;
std::shared_ptr<bool> mIsAlive;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_DEVICE_H_

View File

@@ -1,101 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Instance.h"
#include "dawn_wire/client/Client.h"
namespace dawn::wire::client {
Instance::~Instance() {
mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
request->callback(WGPURequestAdapterStatus_Unknown, nullptr,
"Instance destroyed before callback", request->userdata);
});
}
void Instance::CancelCallbacksForDisconnect() {
mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
request->callback(WGPURequestAdapterStatus_Unknown, nullptr, "GPU connection lost",
request->userdata);
});
}
void Instance::RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
callback(WGPURequestAdapterStatus_Error, nullptr, "GPU connection lost", userdata);
return;
}
auto* allocation = client->AdapterAllocator().New(client);
uint64_t serial = mRequestAdapterRequests.Add({callback, allocation->object->id, userdata});
InstanceRequestAdapterCmd cmd;
cmd.instanceId = this->id;
cmd.requestSerial = serial;
cmd.adapterObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
cmd.options = options;
client->SerializeCommand(cmd);
}
bool Client::DoInstanceRequestAdapterCallback(Instance* instance,
uint64_t requestSerial,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
// May have been deleted or recreated so this isn't an error.
if (instance == nullptr) {
return true;
}
return instance->OnRequestAdapterCallback(requestSerial, status, message, properties,
limits, featuresCount, features);
}
bool Instance::OnRequestAdapterCallback(uint64_t requestSerial,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features) {
RequestAdapterData request;
if (!mRequestAdapterRequests.Acquire(requestSerial, &request)) {
return false;
}
Adapter* adapter = client->AdapterAllocator().GetObject(request.adapterObjectId);
// If the return status is a failure we should give a null adapter to the callback and
// free the allocation.
if (status != WGPURequestAdapterStatus_Success) {
client->AdapterAllocator().Free(adapter);
request.callback(status, nullptr, message, request.userdata);
return true;
}
adapter->SetProperties(properties);
adapter->SetLimits(limits);
adapter->SetFeatures(features, featuresCount);
request.callback(status, ToAPI(adapter), message, request.userdata);
return true;
}
} // namespace dawn::wire::client

View File

@@ -1,56 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_INSTANCE_H_
#define DAWNWIRE_CLIENT_INSTANCE_H_
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
namespace dawn::wire::client {
class Instance final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
~Instance();
void CancelCallbacksForDisconnect() override;
void RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata);
bool OnRequestAdapterCallback(uint64_t requestSerial,
WGPURequestAdapterStatus status,
const char* message,
const WGPUAdapterProperties* properties,
const WGPUSupportedLimits* limits,
uint32_t featuresCount,
const WGPUFeatureName* features);
private:
struct RequestAdapterData {
WGPURequestAdapterCallback callback = nullptr;
ObjectId adapterObjectId;
void* userdata = nullptr;
};
RequestTracker<RequestAdapterData> mRequestAdapterRequests;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_INSTANCE_H_

View File

@@ -1,63 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/LimitsAndFeatures.h"
#include "dawn/common/Assert.h"
#include "dawn_wire/SupportedFeatures.h"
namespace dawn::wire::client {
bool LimitsAndFeatures::GetLimits(WGPUSupportedLimits* limits) const {
ASSERT(limits != nullptr);
if (limits->nextInChain != nullptr) {
return false;
}
*limits = mLimits;
return true;
}
bool LimitsAndFeatures::HasFeature(WGPUFeatureName feature) const {
return mFeatures.count(feature) != 0;
}
size_t LimitsAndFeatures::EnumerateFeatures(WGPUFeatureName* features) const {
if (features != nullptr) {
for (WGPUFeatureName f : mFeatures) {
*features = f;
++features;
}
}
return mFeatures.size();
}
void LimitsAndFeatures::SetLimits(const WGPUSupportedLimits* limits) {
ASSERT(limits != nullptr);
mLimits = *limits;
mLimits.nextInChain = nullptr;
}
void LimitsAndFeatures::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
ASSERT(features != nullptr || featuresCount == 0);
for (uint32_t i = 0; i < featuresCount; ++i) {
// Filter out features that the server supports, but the client does not.
// (Could be different versions)
if (!IsFeatureSupported(features[i])) {
continue;
}
mFeatures.insert(features[i]);
}
}
} // namespace dawn::wire::client

View File

@@ -1,40 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_LIMITSANDFEATURES_H_
#define DAWNWIRE_CLIENT_LIMITSANDFEATURES_H_
#include <dawn/webgpu.h>
#include <unordered_set>
namespace dawn::wire::client {
class LimitsAndFeatures {
public:
bool GetLimits(WGPUSupportedLimits* limits) const;
bool HasFeature(WGPUFeatureName feature) const;
size_t EnumerateFeatures(WGPUFeatureName* features) const;
void SetLimits(const WGPUSupportedLimits* limits);
void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
private:
WGPUSupportedLimits mLimits;
std::unordered_set<WGPUFeatureName> mFeatures;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_LIMITSANDFEATURES_H_

View File

@@ -1,110 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_
#define DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_
#include "dawn/common/Assert.h"
#include "dawn/common/Compiler.h"
#include "dawn_wire/WireCmd_autogen.h"
#include <limits>
#include <memory>
#include <vector>
namespace dawn::wire::client {
template <typename T>
class ObjectAllocator {
public:
struct ObjectAndSerial {
ObjectAndSerial(std::unique_ptr<T> object, uint32_t generation)
: object(std::move(object)), generation(generation) {
}
std::unique_ptr<T> object;
uint32_t generation;
};
ObjectAllocator() {
// ID 0 is nullptr
mObjects.emplace_back(nullptr, 0);
}
template <typename Client>
ObjectAndSerial* New(Client* client) {
uint32_t id = GetNewId();
auto object = std::make_unique<T>(client, 1, id);
client->TrackObject(object.get());
if (id >= mObjects.size()) {
ASSERT(id == mObjects.size());
mObjects.emplace_back(std::move(object), 0);
} else {
ASSERT(mObjects[id].object == nullptr);
mObjects[id].generation++;
// The generation should never overflow. We don't recycle ObjectIds that would
// overflow their next generation.
ASSERT(mObjects[id].generation != 0);
mObjects[id].object = std::move(object);
}
return &mObjects[id];
}
void Free(T* obj) {
ASSERT(obj->IsInList());
if (DAWN_LIKELY(mObjects[obj->id].generation != std::numeric_limits<uint32_t>::max())) {
// Only recycle this ObjectId if the generation won't overflow on the next
// allocation.
FreeId(obj->id);
}
mObjects[obj->id].object = nullptr;
}
T* GetObject(uint32_t id) {
if (id >= mObjects.size()) {
return nullptr;
}
return mObjects[id].object.get();
}
uint32_t GetGeneration(uint32_t id) {
if (id >= mObjects.size()) {
return 0;
}
return mObjects[id].generation;
}
private:
uint32_t GetNewId() {
if (mFreeIds.empty()) {
return mCurrentId++;
}
uint32_t id = mFreeIds.back();
mFreeIds.pop_back();
return id;
}
void FreeId(uint32_t id) {
mFreeIds.push_back(id);
}
// 0 is an ID reserved to represent nullptr
uint32_t mCurrentId = 1;
std::vector<uint32_t> mFreeIds;
std::vector<ObjectAndSerial> mObjects;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_

View File

@@ -1,51 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_OBJECTBASE_H_
#define DAWNWIRE_CLIENT_OBJECTBASE_H_
#include <dawn/webgpu.h>
#include "dawn/common/LinkedList.h"
#include "dawn_wire/ObjectType_autogen.h"
namespace dawn::wire::client {
class Client;
// All objects on the client side have:
// - A pointer to the Client to get where to serialize commands
// - The external reference count
// - An ID that is used to refer to this object when talking with the server side
// - A next/prev pointer. They are part of a linked list of objects of the same type.
struct ObjectBase : public LinkNode<ObjectBase> {
ObjectBase(Client* client, uint32_t refcount, uint32_t id)
: client(client), refcount(refcount), id(id) {
}
~ObjectBase() {
RemoveFromList();
}
virtual void CancelCallbacksForDisconnect() {
}
Client* const client;
uint32_t refcount;
const uint32_t id;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_OBJECTBASE_H_

View File

@@ -1,98 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Queue.h"
#include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h"
namespace dawn::wire::client {
Queue::~Queue() {
ClearAllCallbacks(WGPUQueueWorkDoneStatus_Unknown);
}
bool Queue::OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus status) {
OnWorkDoneData request;
if (!mOnWorkDoneRequests.Acquire(requestSerial, &request)) {
return false;
}
request.callback(status, request.userdata);
return true;
}
void Queue::OnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
callback(WGPUQueueWorkDoneStatus_DeviceLost, userdata);
return;
}
uint64_t serial = mOnWorkDoneRequests.Add({callback, userdata});
QueueOnSubmittedWorkDoneCmd cmd;
cmd.queueId = this->id;
cmd.signalValue = signalValue;
cmd.requestSerial = serial;
client->SerializeCommand(cmd);
}
void Queue::WriteBuffer(WGPUBuffer cBuffer,
uint64_t bufferOffset,
const void* data,
size_t size) {
Buffer* buffer = FromAPI(cBuffer);
QueueWriteBufferCmd cmd;
cmd.queueId = id;
cmd.bufferId = buffer->id;
cmd.bufferOffset = bufferOffset;
cmd.data = static_cast<const uint8_t*>(data);
cmd.size = size;
client->SerializeCommand(cmd);
}
void Queue::WriteTexture(const WGPUImageCopyTexture* destination,
const void* data,
size_t dataSize,
const WGPUTextureDataLayout* dataLayout,
const WGPUExtent3D* writeSize) {
QueueWriteTextureCmd cmd;
cmd.queueId = id;
cmd.destination = destination;
cmd.data = static_cast<const uint8_t*>(data);
cmd.dataSize = dataSize;
cmd.dataLayout = dataLayout;
cmd.writeSize = writeSize;
client->SerializeCommand(cmd);
}
void Queue::CancelCallbacksForDisconnect() {
ClearAllCallbacks(WGPUQueueWorkDoneStatus_DeviceLost);
}
void Queue::ClearAllCallbacks(WGPUQueueWorkDoneStatus status) {
mOnWorkDoneRequests.CloseAll([status](OnWorkDoneData* request) {
if (request->callback != nullptr) {
request->callback(status, request->userdata);
}
});
}
} // namespace dawn::wire::client

View File

@@ -1,57 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_QUEUE_H_
#define DAWNWIRE_CLIENT_QUEUE_H_
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
namespace dawn::wire::client {
class Queue final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
~Queue();
bool OnWorkDoneCallback(uint64_t requestSerial, WGPUQueueWorkDoneStatus status);
// Dawn API
void OnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata);
void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
void WriteTexture(const WGPUImageCopyTexture* destination,
const void* data,
size_t dataSize,
const WGPUTextureDataLayout* dataLayout,
const WGPUExtent3D* writeSize);
private:
void CancelCallbacksForDisconnect() override;
void ClearAllCallbacks(WGPUQueueWorkDoneStatus status);
struct OnWorkDoneData {
WGPUQueueWorkDoneCallback callback = nullptr;
void* userdata = nullptr;
};
RequestTracker<OnWorkDoneData> mOnWorkDoneRequests;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_QUEUE_H_

View File

@@ -1,82 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_REQUESTTRACKER_H_
#define DAWNWIRE_CLIENT_REQUESTTRACKER_H_
#include "dawn/common/Assert.h"
#include "dawn/common/NonCopyable.h"
#include <cstdint>
#include <map>
namespace dawn::wire::client {
class Device;
class MemoryTransferService;
template <typename Request>
class RequestTracker : NonCopyable {
public:
~RequestTracker() {
ASSERT(mRequests.empty());
}
uint64_t Add(Request&& request) {
mSerial++;
mRequests.emplace(mSerial, request);
return mSerial;
}
bool Acquire(uint64_t serial, Request* request) {
auto it = mRequests.find(serial);
if (it == mRequests.end()) {
return false;
}
*request = std::move(it->second);
mRequests.erase(it);
return true;
}
template <typename CloseFunc>
void CloseAll(CloseFunc&& closeFunc) {
// Call closeFunc on all requests while handling reentrancy where the callback of some
// requests may add some additional requests. We guarantee all callbacks for requests
// are called exactly onces, so keep closing new requests if the first batch added more.
// It is fine to loop infinitely here if that's what the application makes use do.
while (!mRequests.empty()) {
// Move mRequests to a local variable so that further reentrant modifications of
// mRequests don't invalidate the iterators.
auto allRequests = std::move(mRequests);
for (auto& [_, request] : allRequests) {
closeFunc(&request);
}
}
}
template <typename F>
void ForAll(F&& f) {
for (auto& [_, request] : mRequests) {
f(&request);
}
}
private:
uint64_t mSerial;
std::map<uint64_t, Request> mRequests;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_REQUESTTRACKER_H_

View File

@@ -1,64 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/ShaderModule.h"
#include "dawn_wire/client/Client.h"
namespace dawn::wire::client {
ShaderModule::~ShaderModule() {
ClearAllCallbacks(WGPUCompilationInfoRequestStatus_Unknown);
}
void ShaderModule::GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata) {
if (client->IsDisconnected()) {
callback(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, userdata);
return;
}
uint64_t serial = mCompilationInfoRequests.Add({callback, userdata});
ShaderModuleGetCompilationInfoCmd cmd;
cmd.shaderModuleId = this->id;
cmd.requestSerial = serial;
client->SerializeCommand(cmd);
}
bool ShaderModule::GetCompilationInfoCallback(uint64_t requestSerial,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info) {
CompilationInfoRequest request;
if (!mCompilationInfoRequests.Acquire(requestSerial, &request)) {
return false;
}
request.callback(status, info, request.userdata);
return true;
}
void ShaderModule::CancelCallbacksForDisconnect() {
ClearAllCallbacks(WGPUCompilationInfoRequestStatus_DeviceLost);
}
void ShaderModule::ClearAllCallbacks(WGPUCompilationInfoRequestStatus status) {
mCompilationInfoRequests.CloseAll([status](CompilationInfoRequest* request) {
if (request->callback != nullptr) {
request->callback(status, nullptr, request->userdata);
}
});
}
} // namespace dawn::wire::client

View File

@@ -1,48 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_SHADER_MODULE_H_
#define DAWNWIRE_CLIENT_SHADER_MODULE_H_
#include <dawn/webgpu.h>
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
namespace dawn::wire::client {
class ShaderModule final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
~ShaderModule();
void GetCompilationInfo(WGPUCompilationInfoCallback callback, void* userdata);
bool GetCompilationInfoCallback(uint64_t requestSerial,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info);
private:
void CancelCallbacksForDisconnect() override;
void ClearAllCallbacks(WGPUCompilationInfoRequestStatus status);
struct CompilationInfoRequest {
WGPUCompilationInfoCallback callback = nullptr;
void* userdata = nullptr;
};
RequestTracker<CompilationInfoRequest> mCompilationInfoRequests;
};
} // namespace dawn::wire::client
#endif // DAWNWIRE_CLIENT_SHADER_MODULE_H_

View File

@@ -1,228 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_SERVER_OBJECTSTORAGE_H_
#define DAWNWIRE_SERVER_OBJECTSTORAGE_H_
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/WireServer.h"
#include <algorithm>
#include <map>
#include <unordered_set>
namespace dawn::wire::server {
struct DeviceInfo {
std::unordered_set<uint64_t> childObjectTypesAndIds;
Server* server;
ObjectHandle self;
};
// Whether this object has been allocated, or reserved for async object creation.
// Used by the KnownObjects queries
enum class AllocationState : uint32_t {
Free,
Reserved,
Allocated,
};
template <typename T>
struct ObjectDataBase {
// The backend-provided handle and generation to this object.
T handle;
uint32_t generation = 0;
AllocationState state;
// This points to an allocation that is owned by the device.
DeviceInfo* deviceInfo = nullptr;
};
// Stores what the backend knows about the type.
template <typename T>
struct ObjectData : public ObjectDataBase<T> {};
enum class BufferMapWriteState { Unmapped, Mapped, MapError };
template <>
struct ObjectData<WGPUBuffer> : public ObjectDataBase<WGPUBuffer> {
// TODO(enga): Use a tagged pointer to save space.
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle;
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle;
BufferMapWriteState mapWriteState = BufferMapWriteState::Unmapped;
WGPUBufferUsageFlags usage = WGPUBufferUsage_None;
// Indicate if writeHandle needs to be destroyed on unmap
bool mappedAtCreation = false;
};
// Pack the ObjectType and ObjectId as a single value for storage in
// an std::unordered_set. This lets us avoid providing our own hash and
// equality comparison operators.
inline uint64_t PackObjectTypeAndId(ObjectType type, ObjectId id) {
static_assert(sizeof(ObjectType) * 8 <= 32);
static_assert(sizeof(ObjectId) * 8 <= 32);
return (static_cast<uint64_t>(type) << 32) + id;
}
inline std::pair<ObjectType, ObjectId> UnpackObjectTypeAndId(uint64_t payload) {
ObjectType type = static_cast<ObjectType>(payload >> 32);
ObjectId id = payload & 0xFFFFFFFF;
return std::make_pair(type, id);
}
template <>
struct ObjectData<WGPUDevice> : public ObjectDataBase<WGPUDevice> {
// Store |info| as a separate allocation so that its address does not move.
// The pointer to |info| is stored in device child objects.
std::unique_ptr<DeviceInfo> info = std::make_unique<DeviceInfo>();
};
// Keeps track of the mapping between client IDs and backend objects.
template <typename T>
class KnownObjects {
public:
using Data = ObjectData<T>;
KnownObjects() {
// Reserve ID 0 so that it can be used to represent nullptr for optional object values
// in the wire format. However don't tag it as allocated so that it is an error to ask
// KnownObjects for ID 0.
Data reservation;
reservation.handle = nullptr;
reservation.state = AllocationState::Free;
mKnown.push_back(std::move(reservation));
}
// Get a backend objects for a given client ID.
// Returns nullptr if the ID hasn't previously been allocated.
const Data* Get(uint32_t id, AllocationState expected = AllocationState::Allocated) const {
if (id >= mKnown.size()) {
return nullptr;
}
const Data* data = &mKnown[id];
if (data->state != expected) {
return nullptr;
}
return data;
}
Data* Get(uint32_t id, AllocationState expected = AllocationState::Allocated) {
if (id >= mKnown.size()) {
return nullptr;
}
Data* data = &mKnown[id];
if (data->state != expected) {
return nullptr;
}
return data;
}
// Allocates the data for a given ID and returns it.
// Returns nullptr if the ID is already allocated, or too far ahead, or if ID is 0 (ID 0 is
// reserved for nullptr). Invalidates all the Data*
Data* Allocate(uint32_t id, AllocationState state = AllocationState::Allocated) {
if (id == 0 || id > mKnown.size()) {
return nullptr;
}
Data data;
data.state = state;
data.handle = nullptr;
if (id >= mKnown.size()) {
mKnown.push_back(std::move(data));
return &mKnown.back();
}
if (mKnown[id].state != AllocationState::Free) {
return nullptr;
}
mKnown[id] = std::move(data);
return &mKnown[id];
}
// Marks an ID as deallocated
void Free(uint32_t id) {
ASSERT(id < mKnown.size());
mKnown[id].state = AllocationState::Free;
}
std::vector<T> AcquireAllHandles() {
std::vector<T> objects;
for (Data& data : mKnown) {
if (data.state == AllocationState::Allocated && data.handle != nullptr) {
objects.push_back(data.handle);
data.state = AllocationState::Free;
data.handle = nullptr;
}
}
return objects;
}
std::vector<T> GetAllHandles() {
std::vector<T> objects;
for (Data& data : mKnown) {
if (data.state == AllocationState::Allocated && data.handle != nullptr) {
objects.push_back(data.handle);
}
}
return objects;
}
private:
std::vector<Data> mKnown;
};
// ObjectIds are lost in deserialization. Store the ids of deserialized
// objects here so they can be used in command handlers. This is useful
// for creating ReturnWireCmds which contain client ids
template <typename T>
class ObjectIdLookupTable {
public:
void Store(T key, ObjectId id) {
mTable[key] = id;
}
// Return the cached ObjectId, or 0 (null handle)
ObjectId Get(T key) const {
const auto it = mTable.find(key);
if (it != mTable.end()) {
return it->second;
}
return 0;
}
void Remove(T key) {
auto it = mTable.find(key);
if (it != mTable.end()) {
mTable.erase(it);
}
}
private:
std::map<T, ObjectId> mTable;
};
} // namespace dawn::wire::server
#endif // DAWNWIRE_SERVER_OBJECTSTORAGE_H_

View File

@@ -1,213 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
#include "dawn_wire/WireServer.h"
namespace dawn::wire::server {
Server::Server(const DawnProcTable& procs,
CommandSerializer* serializer,
MemoryTransferService* memoryTransferService)
: mSerializer(serializer),
mProcs(procs),
mMemoryTransferService(memoryTransferService),
mIsAlive(std::make_shared<bool>(true)) {
if (mMemoryTransferService == nullptr) {
// If a MemoryTransferService is not provided, fallback to inline memory.
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
mMemoryTransferService = mOwnedMemoryTransferService.get();
}
}
Server::~Server() {
// Un-set the error and lost callbacks since we cannot forward them
// after the server has been destroyed.
for (WGPUDevice device : DeviceObjects().GetAllHandles()) {
ClearDeviceCallbacks(device);
}
DestroyAllObjects(mProcs);
}
bool Server::InjectTexture(WGPUTexture texture,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
ASSERT(texture != nullptr);
ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId);
if (device == nullptr || device->generation != deviceGeneration) {
return false;
}
ObjectData<WGPUTexture>* data = TextureObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = texture;
data->generation = generation;
data->state = AllocationState::Allocated;
data->deviceInfo = device->info.get();
if (!TrackDeviceChild(data->deviceInfo, ObjectType::Texture, id)) {
return false;
}
// The texture is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.textureReference(texture);
return true;
}
bool Server::InjectSwapChain(WGPUSwapChain swapchain,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration) {
ASSERT(swapchain != nullptr);
ObjectData<WGPUDevice>* device = DeviceObjects().Get(deviceId);
if (device == nullptr || device->generation != deviceGeneration) {
return false;
}
ObjectData<WGPUSwapChain>* data = SwapChainObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = swapchain;
data->generation = generation;
data->state = AllocationState::Allocated;
data->deviceInfo = device->info.get();
if (!TrackDeviceChild(data->deviceInfo, ObjectType::SwapChain, id)) {
return false;
}
// The texture is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.swapChainReference(swapchain);
return true;
}
bool Server::InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation) {
ASSERT(device != nullptr);
ObjectData<WGPUDevice>* data = DeviceObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = device;
data->generation = generation;
data->state = AllocationState::Allocated;
data->info->server = this;
data->info->self = ObjectHandle{id, generation};
// The device is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.deviceReference(device);
// Set callbacks to forward errors to the client.
SetForwardingDeviceCallbacks(data);
return true;
}
bool Server::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) {
ASSERT(instance != nullptr);
ObjectData<WGPUInstance>* data = InstanceObjects().Allocate(id);
if (data == nullptr) {
return false;
}
data->handle = instance;
data->generation = generation;
data->state = AllocationState::Allocated;
// The instance is externally owned so it shouldn't be destroyed when we receive a destroy
// message from the client. Add a reference to counterbalance the eventual release.
mProcs.instanceReference(instance);
return true;
}
WGPUDevice Server::GetDevice(uint32_t id, uint32_t generation) {
ObjectData<WGPUDevice>* data = DeviceObjects().Get(id);
if (data == nullptr || data->generation != generation) {
return nullptr;
}
return data->handle;
}
void Server::SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject) {
// Note: these callbacks are manually inlined here since they do not acquire and
// free their userdata. Also unlike other callbacks, these are cleared and unset when
// the server is destroyed, so we don't need to check if the server is still alive
// inside them.
mProcs.deviceSetUncapturedErrorCallback(
deviceObject->handle,
[](WGPUErrorType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnUncapturedError(info->self, type, message);
},
deviceObject->info.get());
// Set callback to post warning and other infomation to client.
// Almost the same with UncapturedError.
mProcs.deviceSetLoggingCallback(
deviceObject->handle,
[](WGPULoggingType type, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnLogging(info->self, type, message);
},
deviceObject->info.get());
mProcs.deviceSetDeviceLostCallback(
deviceObject->handle,
[](WGPUDeviceLostReason reason, const char* message, void* userdata) {
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
info->server->OnDeviceLost(info->self, reason, message);
},
deviceObject->info.get());
}
void Server::ClearDeviceCallbacks(WGPUDevice device) {
// Un-set the error and lost callbacks since we cannot forward them
// after the server has been destroyed.
mProcs.deviceSetUncapturedErrorCallback(device, nullptr, nullptr);
mProcs.deviceSetLoggingCallback(device, nullptr, nullptr);
mProcs.deviceSetDeviceLostCallback(device, nullptr, nullptr);
}
bool TrackDeviceChild(DeviceInfo* info, ObjectType type, ObjectId id) {
auto [_, inserted] = info->childObjectTypesAndIds.insert(PackObjectTypeAndId(type, id));
if (!inserted) {
// An object of this type and id already exists.
return false;
}
return true;
}
bool UntrackDeviceChild(DeviceInfo* info, ObjectType type, ObjectId id) {
auto& children = info->childObjectTypesAndIds;
auto it = children.find(PackObjectTypeAndId(type, id));
if (it == children.end()) {
// An object of this type and id was already deleted.
return false;
}
children.erase(it);
return true;
}
} // namespace dawn::wire::server

View File

@@ -1,243 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_SERVER_SERVER_H_
#define DAWNWIRE_SERVER_SERVER_H_
#include "dawn_wire/ChunkedCommandSerializer.h"
#include "dawn_wire/server/ServerBase_autogen.h"
namespace dawn::wire::server {
class Server;
class MemoryTransferService;
// CallbackUserdata and its derived classes are intended to be created by
// Server::MakeUserdata<T> and then passed as the userdata argument for Dawn
// callbacks.
// It contains a pointer back to the Server so that the callback can call the
// Server to perform operations like serialization, and it contains a weak pointer
// |serverIsAlive|. If the weak pointer has expired, it means the server has
// been destroyed and the callback must not use the Server pointer.
// To assist with checking |serverIsAlive| and lifetime management of the userdata,
// |ForwardToServer| (defined later in this file) can be used to acquire the userdata,
// return early if |serverIsAlive| has expired, and then forward the arguments
// to userdata->server->MyCallbackHandler.
//
// Example Usage:
//
// struct MyUserdata : CallbackUserdata { uint32_t foo; };
//
// auto userdata = MakeUserdata<MyUserdata>();
// userdata->foo = 2;
//
// callMyCallbackHandler(
// ForwardToServer<&Server::MyCallbackHandler>,
// userdata.release());
//
// void Server::MyCallbackHandler(MyUserdata* userdata, Other args) { }
struct CallbackUserdata {
Server* const server;
std::weak_ptr<bool> const serverIsAlive;
CallbackUserdata() = delete;
CallbackUserdata(Server* server, const std::shared_ptr<bool>& serverIsAlive)
: server(server), serverIsAlive(serverIsAlive) {
}
};
template <auto F>
struct ForwardToServerHelper {
template <typename _>
struct ExtractedTypes;
// 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<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->*F)(data.get(), std::forward<decltype(args)>(args)...);
}
};
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;
ObjectHandle buffer;
WGPUBuffer bufferObj;
uint64_t requestSerial;
uint64_t offset;
uint64_t size;
WGPUMapModeFlags mode;
};
struct ErrorScopeUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle device;
uint64_t requestSerial;
};
struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle shaderModule;
uint64_t requestSerial;
};
struct QueueWorkDoneUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle queue;
uint64_t requestSerial;
};
struct CreatePipelineAsyncUserData : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle device;
uint64_t requestSerial;
ObjectId pipelineObjectID;
};
struct RequestAdapterUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle instance;
uint64_t requestSerial;
ObjectId adapterObjectId;
};
struct RequestDeviceUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle adapter;
uint64_t requestSerial;
ObjectId deviceObjectId;
};
class Server : public ServerBase {
public:
Server(const DawnProcTable& procs,
CommandSerializer* serializer,
MemoryTransferService* memoryTransferService);
~Server() override;
// ChunkedCommandHandler implementation
const volatile char* HandleCommandsImpl(const volatile char* commands,
size_t size) override;
bool InjectTexture(WGPUTexture texture,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration);
bool InjectSwapChain(WGPUSwapChain swapchain,
uint32_t id,
uint32_t generation,
uint32_t deviceId,
uint32_t deviceGeneration);
bool InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation);
bool InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation);
WGPUDevice GetDevice(uint32_t id, uint32_t generation);
template <typename T,
typename Enable = std::enable_if<std::is_base_of<CallbackUserdata, T>::value>>
std::unique_ptr<T> MakeUserdata() {
return std::unique_ptr<T>(new T(this, mIsAlive));
}
private:
template <typename Cmd>
void SerializeCommand(const Cmd& cmd) {
mSerializer.SerializeCommand(cmd);
}
template <typename Cmd, typename ExtraSizeSerializeFn>
void SerializeCommand(const Cmd& cmd,
size_t extraSize,
ExtraSizeSerializeFn&& SerializeExtraSize) {
mSerializer.SerializeCommand(cmd, extraSize, SerializeExtraSize);
}
void SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject);
void ClearDeviceCallbacks(WGPUDevice device);
// Error callbacks
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(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);
void OnCreateRenderPipelineAsyncCallback(CreatePipelineAsyncUserData* userdata,
WGPUCreatePipelineAsyncStatus status,
WGPURenderPipeline pipeline,
const char* message);
void OnShaderModuleGetCompilationInfo(ShaderModuleGetCompilationInfoUserdata* userdata,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info);
void OnRequestAdapterCallback(RequestAdapterUserdata* userdata,
WGPURequestAdapterStatus status,
WGPUAdapter adapter,
const char* message);
void OnRequestDeviceCallback(RequestDeviceUserdata* userdata,
WGPURequestDeviceStatus status,
WGPUDevice device,
const char* message);
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
WireDeserializeAllocator mAllocator;
ChunkedCommandSerializer mSerializer;
DawnProcTable mProcs;
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
MemoryTransferService* mMemoryTransferService = nullptr;
std::shared_ptr<bool> mIsAlive;
};
bool TrackDeviceChild(DeviceInfo* device, ObjectType type, ObjectId id);
bool UntrackDeviceChild(DeviceInfo* device, ObjectType type, ObjectId id);
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
} // namespace dawn::wire::server
#endif // DAWNWIRE_SERVER_SERVER_H_

View File

@@ -1,110 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
#include "dawn_wire/SupportedFeatures.h"
namespace dawn::wire::server {
bool Server::DoAdapterRequestDevice(ObjectId adapterId,
uint64_t requestSerial,
ObjectHandle deviceHandle,
const WGPUDeviceDescriptor* descriptor) {
auto* adapter = AdapterObjects().Get(adapterId);
if (adapter == nullptr) {
return false;
}
auto* resultData = DeviceObjects().Allocate(deviceHandle.id, AllocationState::Reserved);
if (resultData == nullptr) {
return false;
}
resultData->generation = deviceHandle.generation;
auto userdata = MakeUserdata<RequestDeviceUserdata>();
userdata->adapter = ObjectHandle{adapterId, adapter->generation};
userdata->requestSerial = requestSerial;
userdata->deviceObjectId = deviceHandle.id;
mProcs.adapterRequestDevice(adapter->handle, descriptor,
ForwardToServer<&Server::OnRequestDeviceCallback>,
userdata.release());
return true;
}
void Server::OnRequestDeviceCallback(RequestDeviceUserdata* data,
WGPURequestDeviceStatus status,
WGPUDevice device,
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.
ASSERT(deviceObject != nullptr);
ReturnAdapterRequestDeviceCallbackCmd cmd = {};
cmd.adapter = data->adapter;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
cmd.message = message;
if (status != WGPURequestDeviceStatus_Success) {
// Free the ObjectId which will make it unusable.
DeviceObjects().Free(data->deviceObjectId);
ASSERT(device == nullptr);
SerializeCommand(cmd);
return;
}
std::vector<WGPUFeatureName> features;
size_t featuresCount = mProcs.deviceEnumerateFeatures(device, nullptr);
features.resize(featuresCount);
mProcs.deviceEnumerateFeatures(device, features.data());
// The client should only be able to request supported features, so all enumerated
// features that were enabled must also be supported by the wire.
// Note: We fail the callback here, instead of immediately upon receiving
// the request to preserve callback ordering.
for (WGPUFeatureName f : features) {
if (!IsFeatureSupported(f)) {
// Release the device.
mProcs.deviceRelease(device);
// Free the ObjectId which will make it unusable.
DeviceObjects().Free(data->deviceObjectId);
cmd.status = WGPURequestDeviceStatus_Error;
cmd.message = "Requested feature not supported.";
SerializeCommand(cmd);
return;
}
}
cmd.featuresCount = features.size();
cmd.features = features.data();
WGPUSupportedLimits limits = {};
mProcs.deviceGetLimits(device, &limits);
cmd.limits = &limits;
// Assign the handle and allocated status if the device is created successfully.
deviceObject->state = AllocationState::Allocated;
deviceObject->handle = device;
SetForwardingDeviceCallbacks(deviceObject);
SerializeCommand(cmd);
}
} // namespace dawn::wire::server

View File

@@ -1,282 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Assert.h"
#include "dawn_wire/BufferConsumer_impl.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/server/Server.h"
#include <memory>
namespace dawn::wire::server {
bool Server::PreHandleBufferUnmap(const BufferUnmapCmd& cmd) {
auto* buffer = BufferObjects().Get(cmd.selfId);
DAWN_ASSERT(buffer != nullptr);
if (buffer->mappedAtCreation && !(buffer->usage & WGPUMapMode_Write)) {
// This indicates the writeHandle is for mappedAtCreation only. Destroy on unmap
// writeHandle could have possibly been deleted if buffer is already destroyed so we
// don't assert it's non-null
buffer->writeHandle = nullptr;
}
buffer->mapWriteState = BufferMapWriteState::Unmapped;
return true;
}
bool Server::PreHandleBufferDestroy(const BufferDestroyCmd& cmd) {
// Destroying a buffer does an implicit unmapping.
auto* buffer = BufferObjects().Get(cmd.selfId);
DAWN_ASSERT(buffer != nullptr);
// The buffer was destroyed. Clear the Read/WriteHandle.
buffer->readHandle = nullptr;
buffer->writeHandle = nullptr;
buffer->mapWriteState = BufferMapWriteState::Unmapped;
return true;
}
bool Server::DoBufferMapAsync(ObjectId bufferId,
uint64_t requestSerial,
WGPUMapModeFlags mode,
uint64_t offset64,
uint64_t size64) {
// These requests are just forwarded to the buffer, with userdata containing what the
// client will require in the return command.
// The null object isn't valid as `self`
if (bufferId == 0) {
return false;
}
auto* buffer = BufferObjects().Get(bufferId);
if (buffer == nullptr) {
return false;
}
std::unique_ptr<MapUserdata> userdata = MakeUserdata<MapUserdata>();
userdata->buffer = ObjectHandle{bufferId, buffer->generation};
userdata->bufferObj = buffer->handle;
userdata->requestSerial = requestSerial;
userdata->mode = mode;
// Make sure that the deserialized offset and size are no larger than
// std::numeric_limits<size_t>::max() so that they are CPU-addressable, and size is not
// WGPU_WHOLE_MAP_SIZE, which is by definition std::numeric_limits<size_t>::max(). Since
// 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(userdata.get(), WGPUBufferMapAsyncStatus_Error);
return true;
}
size_t offset = static_cast<size_t>(offset64);
size_t size = static_cast<size_t>(size64);
userdata->offset = offset;
userdata->size = size;
mProcs.bufferMapAsync(buffer->handle, mode, offset, size,
ForwardToServer<&Server::OnBufferMapAsyncCallback>,
userdata.release());
return true;
}
bool Server::DoDeviceCreateBuffer(ObjectId deviceId,
const WGPUBufferDescriptor* descriptor,
ObjectHandle bufferResult,
uint64_t readHandleCreateInfoLength,
const uint8_t* readHandleCreateInfo,
uint64_t writeHandleCreateInfoLength,
const uint8_t* writeHandleCreateInfo) {
auto* device = DeviceObjects().Get(deviceId);
if (device == nullptr) {
return false;
}
// Create and register the buffer object.
auto* resultData = BufferObjects().Allocate(bufferResult.id);
if (resultData == nullptr) {
return false;
}
resultData->generation = bufferResult.generation;
resultData->handle = mProcs.deviceCreateBuffer(device->handle, descriptor);
resultData->deviceInfo = device->info.get();
resultData->usage = descriptor->usage;
resultData->mappedAtCreation = descriptor->mappedAtCreation;
if (!TrackDeviceChild(resultData->deviceInfo, ObjectType::Buffer, bufferResult.id)) {
return false;
}
// isReadMode and isWriteMode could be true at the same time if usage contains
// WGPUMapMode_Read and buffer is mappedAtCreation
bool isReadMode = descriptor->usage & WGPUMapMode_Read;
bool isWriteMode = descriptor->usage & WGPUMapMode_Write || descriptor->mappedAtCreation;
// This is the size of data deserialized from the command stream to create the read/write
// handle, which must be CPU-addressable.
if (readHandleCreateInfoLength > std::numeric_limits<size_t>::max() ||
writeHandleCreateInfoLength > std::numeric_limits<size_t>::max() ||
readHandleCreateInfoLength >
std::numeric_limits<size_t>::max() - writeHandleCreateInfoLength) {
return false;
}
if (isWriteMode) {
MemoryTransferService::WriteHandle* writeHandle = nullptr;
// Deserialize metadata produced from the client to create a companion server handle.
if (!mMemoryTransferService->DeserializeWriteHandle(
writeHandleCreateInfo, static_cast<size_t>(writeHandleCreateInfoLength),
&writeHandle)) {
return false;
}
ASSERT(writeHandle != nullptr);
resultData->writeHandle.reset(writeHandle);
writeHandle->SetDataLength(descriptor->size);
if (descriptor->mappedAtCreation) {
void* mapping =
mProcs.bufferGetMappedRange(resultData->handle, 0, descriptor->size);
if (mapping == nullptr) {
// A zero mapping is used to indicate an allocation error of an error buffer.
// This is a valid case and isn't fatal. Remember the buffer is an error so as
// to skip subsequent mapping operations.
resultData->mapWriteState = BufferMapWriteState::MapError;
return true;
}
ASSERT(mapping != nullptr);
writeHandle->SetTarget(mapping);
resultData->mapWriteState = BufferMapWriteState::Mapped;
}
}
if (isReadMode) {
MemoryTransferService::ReadHandle* readHandle = nullptr;
// Deserialize metadata produced from the client to create a companion server handle.
if (!mMemoryTransferService->DeserializeReadHandle(
readHandleCreateInfo, static_cast<size_t>(readHandleCreateInfoLength),
&readHandle)) {
return false;
}
ASSERT(readHandle != nullptr);
resultData->readHandle.reset(readHandle);
}
return true;
}
bool Server::DoBufferUpdateMappedData(ObjectId bufferId,
uint64_t writeDataUpdateInfoLength,
const uint8_t* writeDataUpdateInfo,
uint64_t offset,
uint64_t size) {
// The null object isn't valid as `self`
if (bufferId == 0) {
return false;
}
if (writeDataUpdateInfoLength > std::numeric_limits<size_t>::max() ||
offset > std::numeric_limits<size_t>::max() ||
size > std::numeric_limits<size_t>::max()) {
return false;
}
auto* buffer = BufferObjects().Get(bufferId);
if (buffer == nullptr) {
return false;
}
switch (buffer->mapWriteState) {
case BufferMapWriteState::Unmapped:
return false;
case BufferMapWriteState::MapError:
// The buffer is mapped but there was an error allocating mapped data.
// Do not perform the memcpy.
return true;
case BufferMapWriteState::Mapped:
break;
}
if (!buffer->writeHandle) {
// This check is performed after the check for the MapError state. It is permissible
// to Unmap and attempt to update mapped data of an error buffer.
return false;
}
// Deserialize the flush info and flush updated data from the handle into the target
// of the handle. The target is set via WriteHandle::SetTarget.
return buffer->writeHandle->DeserializeDataUpdate(
writeDataUpdateInfo, static_cast<size_t>(writeDataUpdateInfoLength),
static_cast<size_t>(offset), static_cast<size_t>(size));
}
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) {
return;
}
bool isRead = data->mode & WGPUMapMode_Read;
bool isSuccess = status == WGPUBufferMapAsyncStatus_Success;
ReturnBufferMapAsyncCallbackCmd cmd;
cmd.buffer = data->buffer;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
cmd.readDataUpdateInfoLength = 0;
cmd.readDataUpdateInfo = nullptr;
const void* readData = nullptr;
if (isSuccess) {
if (isRead) {
// Get the serialization size of the message to initialize ReadHandle data.
readData =
mProcs.bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
cmd.readDataUpdateInfoLength =
bufferData->readHandle->SizeOfSerializeDataUpdate(data->offset, data->size);
} else {
ASSERT(data->mode & WGPUMapMode_Write);
// The in-flight map request returned successfully.
bufferData->mapWriteState = BufferMapWriteState::Mapped;
// Set the target of the WriteHandle to the mapped buffer data.
// writeHandle Target always refers to the buffer base address.
// but we call getMappedRange exactly with the range of data that is potentially
// modified (i.e. we don't want getMappedRange(0, wholeBufferSize) if only a
// subset of the buffer is actually mapped) in case the implementation does some
// range tracking.
bufferData->writeHandle->SetTarget(
static_cast<uint8_t*>(
mProcs.bufferGetMappedRange(data->bufferObj, data->offset, data->size)) -
data->offset);
}
}
SerializeCommand(cmd, cmd.readDataUpdateInfoLength, [&](SerializeBuffer* serializeBuffer) {
if (isSuccess && isRead) {
char* readHandleBuffer;
WIRE_TRY(serializeBuffer->NextN(cmd.readDataUpdateInfoLength, &readHandleBuffer));
// The in-flight map request returned successfully.
bufferData->readHandle->SerializeDataUpdate(readData, data->offset, data->size,
readHandleBuffer);
}
return WireResult::Success;
});
}
} // namespace dawn::wire::server

View File

@@ -1,204 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
namespace dawn::wire::server {
namespace {
template <ObjectType objectType, typename Pipeline>
void HandleCreateRenderPipelineAsyncCallbackResult(KnownObjects<Pipeline>* knownObjects,
WGPUCreatePipelineAsyncStatus status,
Pipeline pipeline,
CreatePipelineAsyncUserData* data) {
// May be null if the device was destroyed. Device destruction destroys child
// objects on the wire.
auto* pipelineObject =
knownObjects->Get(data->pipelineObjectID, 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.
ASSERT(pipelineObject != nullptr);
if (status == WGPUCreatePipelineAsyncStatus_Success) {
// Assign the handle and allocated status if the pipeline is created successfully.
pipelineObject->state = AllocationState::Allocated;
pipelineObject->handle = pipeline;
// This should be impossible to fail. It would require a command to be sent that
// creates a duplicate ObjectId, which would fail validation.
bool success = TrackDeviceChild(pipelineObject->deviceInfo, objectType,
data->pipelineObjectID);
ASSERT(success);
} else {
// Otherwise, free the ObjectId which will make it unusable.
knownObjects->Free(data->pipelineObjectID);
ASSERT(pipeline == nullptr);
}
}
} // anonymous namespace
void Server::OnUncapturedError(ObjectHandle device, WGPUErrorType type, const char* message) {
ReturnDeviceUncapturedErrorCallbackCmd cmd;
cmd.device = device;
cmd.type = type;
cmd.message = message;
SerializeCommand(cmd);
}
void Server::OnDeviceLost(ObjectHandle device,
WGPUDeviceLostReason reason,
const char* message) {
ReturnDeviceLostCallbackCmd cmd;
cmd.device = device;
cmd.reason = reason;
cmd.message = message;
SerializeCommand(cmd);
}
void Server::OnLogging(ObjectHandle device, WGPULoggingType type, const char* message) {
ReturnDeviceLoggingCallbackCmd cmd;
cmd.device = device;
cmd.type = type;
cmd.message = message;
SerializeCommand(cmd);
}
bool Server::DoDevicePopErrorScope(ObjectId deviceId, uint64_t requestSerial) {
auto* device = DeviceObjects().Get(deviceId);
if (device == nullptr) {
return false;
}
auto userdata = MakeUserdata<ErrorScopeUserdata>();
userdata->requestSerial = requestSerial;
userdata->device = ObjectHandle{deviceId, device->generation};
ErrorScopeUserdata* unownedUserdata = userdata.release();
bool success = mProcs.devicePopErrorScope(
device->handle, ForwardToServer<&Server::OnDevicePopErrorScope>, unownedUserdata);
if (!success) {
delete unownedUserdata;
}
return success;
}
void Server::OnDevicePopErrorScope(ErrorScopeUserdata* userdata,
WGPUErrorType type,
const char* message) {
ReturnDevicePopErrorScopeCallbackCmd cmd;
cmd.device = userdata->device;
cmd.requestSerial = userdata->requestSerial;
cmd.type = type;
cmd.message = message;
SerializeCommand(cmd);
}
bool Server::DoDeviceCreateComputePipelineAsync(
ObjectId deviceId,
uint64_t requestSerial,
ObjectHandle pipelineObjectHandle,
const WGPUComputePipelineDescriptor* descriptor) {
auto* device = DeviceObjects().Get(deviceId);
if (device == nullptr) {
return false;
}
auto* resultData =
ComputePipelineObjects().Allocate(pipelineObjectHandle.id, AllocationState::Reserved);
if (resultData == nullptr) {
return false;
}
resultData->generation = pipelineObjectHandle.generation;
resultData->deviceInfo = device->info.get();
auto userdata = MakeUserdata<CreatePipelineAsyncUserData>();
userdata->device = ObjectHandle{deviceId, device->generation};
userdata->requestSerial = requestSerial;
userdata->pipelineObjectID = pipelineObjectHandle.id;
mProcs.deviceCreateComputePipelineAsync(
device->handle, descriptor,
ForwardToServer<&Server::OnCreateComputePipelineAsyncCallback>, userdata.release());
return true;
}
void Server::OnCreateComputePipelineAsyncCallback(CreatePipelineAsyncUserData* data,
WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,
const char* message) {
HandleCreateRenderPipelineAsyncCallbackResult<ObjectType::ComputePipeline>(
&ComputePipelineObjects(), status, pipeline, data);
ReturnDeviceCreateComputePipelineAsyncCallbackCmd cmd;
cmd.device = data->device;
cmd.status = status;
cmd.requestSerial = data->requestSerial;
cmd.message = message;
SerializeCommand(cmd);
}
bool Server::DoDeviceCreateRenderPipelineAsync(ObjectId deviceId,
uint64_t requestSerial,
ObjectHandle pipelineObjectHandle,
const WGPURenderPipelineDescriptor* descriptor) {
auto* device = DeviceObjects().Get(deviceId);
if (device == nullptr) {
return false;
}
auto* resultData =
RenderPipelineObjects().Allocate(pipelineObjectHandle.id, AllocationState::Reserved);
if (resultData == nullptr) {
return false;
}
resultData->generation = pipelineObjectHandle.generation;
resultData->deviceInfo = device->info.get();
auto userdata = MakeUserdata<CreatePipelineAsyncUserData>();
userdata->device = ObjectHandle{deviceId, device->generation};
userdata->requestSerial = requestSerial;
userdata->pipelineObjectID = pipelineObjectHandle.id;
mProcs.deviceCreateRenderPipelineAsync(
device->handle, descriptor,
ForwardToServer<&Server::OnCreateRenderPipelineAsyncCallback>, userdata.release());
return true;
}
void Server::OnCreateRenderPipelineAsyncCallback(CreatePipelineAsyncUserData* data,
WGPUCreatePipelineAsyncStatus status,
WGPURenderPipeline pipeline,
const char* message) {
HandleCreateRenderPipelineAsyncCallbackResult<ObjectType::RenderPipeline>(
&RenderPipelineObjects(), status, pipeline, data);
ReturnDeviceCreateRenderPipelineAsyncCallbackCmd cmd;
cmd.device = data->device;
cmd.status = status;
cmd.requestSerial = data->requestSerial;
cmd.message = message;
SerializeCommand(cmd);
}
} // namespace dawn::wire::server

View File

@@ -1,94 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Assert.h"
#include "dawn_wire/WireServer.h"
#include "dawn_wire/server/Server.h"
#include <cstring>
namespace dawn::wire::server {
class InlineMemoryTransferService : public MemoryTransferService {
public:
class ReadHandleImpl : public ReadHandle {
public:
ReadHandleImpl() {
}
~ReadHandleImpl() override = default;
size_t SizeOfSerializeDataUpdate(size_t offset, size_t size) override {
return size;
}
void SerializeDataUpdate(const void* data,
size_t offset,
size_t size,
void* serializePointer) override {
if (size > 0) {
ASSERT(data != nullptr);
ASSERT(serializePointer != nullptr);
memcpy(serializePointer, data, size);
}
}
};
class WriteHandleImpl : public WriteHandle {
public:
WriteHandleImpl() {
}
~WriteHandleImpl() override = default;
bool DeserializeDataUpdate(const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) override {
if (deserializeSize != size || mTargetData == nullptr ||
deserializePointer == nullptr) {
return false;
}
if ((offset >= mDataLength && offset > 0) || size > mDataLength - offset) {
return false;
}
memcpy(static_cast<uint8_t*>(mTargetData) + offset, deserializePointer, size);
return true;
}
};
InlineMemoryTransferService() {
}
~InlineMemoryTransferService() override = default;
bool DeserializeReadHandle(const void* deserializePointer,
size_t deserializeSize,
ReadHandle** readHandle) override {
ASSERT(readHandle != nullptr);
*readHandle = new ReadHandleImpl();
return true;
}
bool DeserializeWriteHandle(const void* deserializePointer,
size_t deserializeSize,
WriteHandle** writeHandle) override {
ASSERT(writeHandle != nullptr);
*writeHandle = new WriteHandleImpl();
return true;
}
};
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService() {
return std::make_unique<InlineMemoryTransferService>();
}
} // namespace dawn::wire::server

View File

@@ -1,100 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
#include "dawn_wire/SupportedFeatures.h"
#include <algorithm>
namespace dawn::wire::server {
bool Server::DoInstanceRequestAdapter(ObjectId instanceId,
uint64_t requestSerial,
ObjectHandle adapterHandle,
const WGPURequestAdapterOptions* options) {
auto* instance = InstanceObjects().Get(instanceId);
if (instance == nullptr) {
return false;
}
auto* resultData = AdapterObjects().Allocate(adapterHandle.id, AllocationState::Reserved);
if (resultData == nullptr) {
return false;
}
resultData->generation = adapterHandle.generation;
auto userdata = MakeUserdata<RequestAdapterUserdata>();
userdata->instance = ObjectHandle{instanceId, instance->generation};
userdata->requestSerial = requestSerial;
userdata->adapterObjectId = adapterHandle.id;
mProcs.instanceRequestAdapter(instance->handle, options,
ForwardToServer<&Server::OnRequestAdapterCallback>,
userdata.release());
return true;
}
void Server::OnRequestAdapterCallback(RequestAdapterUserdata* data,
WGPURequestAdapterStatus status,
WGPUAdapter adapter,
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
// they move from Reserved to Allocated, or if they are destroyed here.
ASSERT(adapterObject != nullptr);
ReturnInstanceRequestAdapterCallbackCmd cmd = {};
cmd.instance = data->instance;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
cmd.message = message;
if (status != WGPURequestAdapterStatus_Success) {
// Free the ObjectId which will make it unusable.
AdapterObjects().Free(data->adapterObjectId);
ASSERT(adapter == nullptr);
SerializeCommand(cmd);
return;
}
WGPUAdapterProperties properties = {};
WGPUSupportedLimits limits = {};
std::vector<WGPUFeatureName> features;
// Assign the handle and allocated status if the adapter is created successfully.
adapterObject->state = AllocationState::Allocated;
adapterObject->handle = adapter;
size_t featuresCount = mProcs.adapterEnumerateFeatures(adapter, nullptr);
features.resize(featuresCount);
mProcs.adapterEnumerateFeatures(adapter, features.data());
// Hide features the wire cannot support.
auto it = std::partition(features.begin(), features.end(), IsFeatureSupported);
cmd.featuresCount = std::distance(features.begin(), it);
cmd.features = features.data();
mProcs.adapterGetProperties(adapter, &properties);
mProcs.adapterGetLimits(adapter, &limits);
cmd.properties = &properties;
cmd.limits = &limits;
SerializeCommand(cmd);
}
} // namespace dawn::wire::server

View File

@@ -1,91 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/ServerMemoryTransferService_mock.h"
#include "dawn/common/Assert.h"
namespace dawn::wire::server {
MockMemoryTransferService::MockReadHandle::MockReadHandle(MockMemoryTransferService* service)
: ReadHandle(), mService(service) {
}
MockMemoryTransferService::MockReadHandle::~MockReadHandle() {
mService->OnReadHandleDestroy(this);
}
size_t MockMemoryTransferService::MockReadHandle::SizeOfSerializeDataUpdate(size_t offset,
size_t size) {
return mService->OnReadHandleSizeOfSerializeDataUpdate(this, offset, size);
}
void MockMemoryTransferService::MockReadHandle::SerializeDataUpdate(const void* data,
size_t offset,
size_t size,
void* serializePointer) {
mService->OnReadHandleSerializeDataUpdate(this, data, offset, size, serializePointer);
}
MockMemoryTransferService::MockWriteHandle::MockWriteHandle(MockMemoryTransferService* service)
: WriteHandle(), mService(service) {
}
MockMemoryTransferService::MockWriteHandle::~MockWriteHandle() {
mService->OnWriteHandleDestroy(this);
}
const uint32_t* MockMemoryTransferService::MockWriteHandle::GetData() const {
return reinterpret_cast<const uint32_t*>(mTargetData);
}
bool MockMemoryTransferService::MockWriteHandle::DeserializeDataUpdate(
const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) {
ASSERT(deserializeSize % sizeof(uint32_t) == 0);
return mService->OnWriteHandleDeserializeDataUpdate(
this, reinterpret_cast<const uint32_t*>(deserializePointer), deserializeSize, offset,
size);
}
MockMemoryTransferService::MockMemoryTransferService() = default;
MockMemoryTransferService::~MockMemoryTransferService() = default;
bool MockMemoryTransferService::DeserializeReadHandle(const void* deserializePointer,
size_t deserializeSize,
ReadHandle** readHandle) {
ASSERT(deserializeSize % sizeof(uint32_t) == 0);
return OnDeserializeReadHandle(reinterpret_cast<const uint32_t*>(deserializePointer),
deserializeSize, readHandle);
}
bool MockMemoryTransferService::DeserializeWriteHandle(const void* deserializePointer,
size_t deserializeSize,
WriteHandle** writeHandle) {
ASSERT(deserializeSize % sizeof(uint32_t) == 0);
return OnDeserializeWriteHandle(reinterpret_cast<const uint32_t*>(deserializePointer),
deserializeSize, writeHandle);
}
MockMemoryTransferService::MockReadHandle* MockMemoryTransferService::NewReadHandle() {
return new MockReadHandle(this);
}
MockMemoryTransferService::MockWriteHandle* MockMemoryTransferService::NewWriteHandle() {
return new MockWriteHandle(this);
}
} // namespace dawn::wire::server

View File

@@ -1,108 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_
#define DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_
#include <gmock/gmock.h>
#include "dawn_wire/WireServer.h"
#include "dawn_wire/server/Server.h"
namespace dawn::wire::server {
class MockMemoryTransferService : public MemoryTransferService {
public:
class MockReadHandle : public ReadHandle {
public:
MockReadHandle(MockMemoryTransferService* service);
~MockReadHandle() override;
size_t SizeOfSerializeDataUpdate(size_t offset, size_t size) override;
void SerializeDataUpdate(const void* data,
size_t offset,
size_t size,
void* serializePointer) override;
private:
MockMemoryTransferService* mService;
};
class MockWriteHandle : public WriteHandle {
public:
MockWriteHandle(MockMemoryTransferService* service);
~MockWriteHandle() override;
bool DeserializeDataUpdate(const void* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size) override;
const uint32_t* GetData() const;
private:
MockMemoryTransferService* mService;
};
MockMemoryTransferService();
~MockMemoryTransferService() override;
bool DeserializeReadHandle(const void* deserializePointer,
size_t deserializeSize,
ReadHandle** readHandle) override;
bool DeserializeWriteHandle(const void* deserializePointer,
size_t deserializeSize,
WriteHandle** writeHandle) override;
MockReadHandle* NewReadHandle();
MockWriteHandle* NewWriteHandle();
MOCK_METHOD(bool,
OnDeserializeReadHandle,
(const uint32_t* deserializePointer,
size_t deserializeSize,
ReadHandle** readHandle));
MOCK_METHOD(bool,
OnDeserializeWriteHandle,
(const uint32_t* deserializePointer,
size_t deserializeSize,
WriteHandle** writeHandle));
MOCK_METHOD(size_t,
OnReadHandleSizeOfSerializeDataUpdate,
(const ReadHandle* readHandle, size_t offset, size_t size));
MOCK_METHOD(void,
OnReadHandleSerializeDataUpdate,
(const ReadHandle* readHandle,
const void* data,
size_t offset,
size_t size,
void* serializePointer));
MOCK_METHOD(void, OnReadHandleDestroy, (const ReadHandle* readHandle));
MOCK_METHOD(bool,
OnWriteHandleDeserializeDataUpdate,
(const WriteHandle* writeHandle,
const uint32_t* deserializePointer,
size_t deserializeSize,
size_t offset,
size_t size));
MOCK_METHOD(void, OnWriteHandleDestroy, (const WriteHandle* writeHandle));
};
} // namespace dawn::wire::server
#endif // DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_

View File

@@ -1,103 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/common/Assert.h"
#include "dawn_wire/server/Server.h"
namespace dawn::wire::server {
void Server::OnQueueWorkDone(QueueWorkDoneUserdata* data, WGPUQueueWorkDoneStatus status) {
ReturnQueueWorkDoneCallbackCmd cmd;
cmd.queue = data->queue;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
SerializeCommand(cmd);
}
bool Server::DoQueueOnSubmittedWorkDone(ObjectId queueId,
uint64_t signalValue,
uint64_t requestSerial) {
auto* queue = QueueObjects().Get(queueId);
if (queue == nullptr) {
return false;
}
auto userdata = MakeUserdata<QueueWorkDoneUserdata>();
userdata->queue = ObjectHandle{queueId, queue->generation};
userdata->requestSerial = requestSerial;
mProcs.queueOnSubmittedWorkDone(queue->handle, signalValue,
ForwardToServer<&Server::OnQueueWorkDone>,
userdata.release());
return true;
}
bool Server::DoQueueWriteBuffer(ObjectId queueId,
ObjectId bufferId,
uint64_t bufferOffset,
const uint8_t* data,
uint64_t size) {
// The null object isn't valid as `self` or `buffer` so we can combine the check with the
// check that the ID is valid.
auto* queue = QueueObjects().Get(queueId);
auto* buffer = BufferObjects().Get(bufferId);
if (queue == nullptr || buffer == nullptr) {
return false;
}
if (size > std::numeric_limits<size_t>::max()) {
auto* device = DeviceObjects().Get(queue->deviceInfo->self.id);
if (device == nullptr) {
return false;
}
return DoDeviceInjectError(reinterpret_cast<WGPUDevice>(device),
WGPUErrorType_OutOfMemory,
"Data size too large for write texture.");
}
mProcs.queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, data,
static_cast<size_t>(size));
return true;
}
bool Server::DoQueueWriteTexture(ObjectId queueId,
const WGPUImageCopyTexture* destination,
const uint8_t* data,
uint64_t dataSize,
const WGPUTextureDataLayout* dataLayout,
const WGPUExtent3D* writeSize) {
// The null object isn't valid as `self` so we can combine the check with the
// check that the ID is valid.
auto* queue = QueueObjects().Get(queueId);
if (queue == nullptr) {
return false;
}
if (dataSize > std::numeric_limits<size_t>::max()) {
auto* device = DeviceObjects().Get(queue->deviceInfo->self.id);
if (device == nullptr) {
return false;
}
return DoDeviceInjectError(reinterpret_cast<WGPUDevice>(device),
WGPUErrorType_OutOfMemory,
"Data size too large for write texture.");
}
mProcs.queueWriteTexture(queue->handle, destination, data, static_cast<size_t>(dataSize),
dataLayout, writeSize);
return true;
}
} // namespace dawn::wire::server

View File

@@ -1,49 +0,0 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
#include <memory>
namespace dawn::wire::server {
bool Server::DoShaderModuleGetCompilationInfo(ObjectId shaderModuleId, uint64_t requestSerial) {
auto* shaderModule = ShaderModuleObjects().Get(shaderModuleId);
if (shaderModule == nullptr) {
return false;
}
auto userdata = MakeUserdata<ShaderModuleGetCompilationInfoUserdata>();
userdata->shaderModule = ObjectHandle{shaderModuleId, shaderModule->generation};
userdata->requestSerial = requestSerial;
mProcs.shaderModuleGetCompilationInfo(
shaderModule->handle, ForwardToServer<&Server::OnShaderModuleGetCompilationInfo>,
userdata.release());
return true;
}
void Server::OnShaderModuleGetCompilationInfo(ShaderModuleGetCompilationInfoUserdata* data,
WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info) {
ReturnShaderModuleGetCompilationInfoCallbackCmd cmd;
cmd.shaderModule = data->shaderModule;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
cmd.info = info;
SerializeCommand(cmd);
}
} // namespace dawn::wire::server