mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-14 23:56:16 +00:00
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:
@@ -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" ]
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user