From 748572894e96b1eab4089da912441ae1b588b2aa Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Wed, 30 Aug 2023 15:24:16 -0400 Subject: [PATCH] emsdk 3.1.45: get code to compile - closes vtk/vtk#19060. - disable IOExportGL2PS for WebAssembly. - handle stat64 vs stat for emscripten in LSDyna and Ensight readers. --- .../docs/advanced/build_wasm_emscripten.md | 10 +++ .../release/dev/update-dawn-webgpu.md | 6 ++ IO/EnSight/vtkEnSight6BinaryReader.cxx | 8 ++ IO/EnSight/vtkEnSightGoldBinaryReader.cxx | 8 ++ IO/ExportGL2PS/vtk.module | 2 +- IO/LSDyna/LSDynaFamily.cxx | 8 ++ Rendering/WebGPU/vtkWGPUContext.cxx | 77 ++++++------------- Rendering/WebGPU/vtkWebGPUActor.cxx | 5 ++ .../WebGPU/vtkWebGPUInternalsShaderModule.cxx | 2 +- Rendering/WebGPU/vtkWebGPURenderWindow.cxx | 38 ++++++--- 10 files changed, 98 insertions(+), 66 deletions(-) create mode 100644 Documentation/release/dev/update-dawn-webgpu.md diff --git a/Documentation/docs/advanced/build_wasm_emscripten.md b/Documentation/docs/advanced/build_wasm_emscripten.md index ceb50ce1115..c58b1a269c3 100644 --- a/Documentation/docs/advanced/build_wasm_emscripten.md +++ b/Documentation/docs/advanced/build_wasm_emscripten.md @@ -54,6 +54,16 @@ For this guide, you will need the following: These instructions use a specific convention for the source, build and install directories that is appropriate when building VTK for wasm inside a docker container. Please replace these _root-directory_ paths if VTK is being built outside a docker container. +### Install emscripten ports (IMPORTANT!) +Emscripten uses SDL2 to connect user input events to the browser event subsystem. The SDL2 port +will need to be built if this is the first time you downloaded the EMSDK. The `embuilder` script +will be on the path if you installed and activated EMSDK as described in the prerequisites. +```bash +$ embuilder build sdl2 +``` + +### Build VTK + 1. Configure the project with CMake. `emcmake` tells CMake to use the `emscripten` toolchain for cross compilation. ```bash diff --git a/Documentation/release/dev/update-dawn-webgpu.md b/Documentation/release/dev/update-dawn-webgpu.md new file mode 100644 index 00000000000..faa8f53bbbe --- /dev/null +++ b/Documentation/release/dev/update-dawn-webgpu.md @@ -0,0 +1,6 @@ +# Update Dawn/WebGPU API in the WebGPU backend + +- `WGPUShaderModuleWGSLDescriptor::source` has now been renamed to `WGPUShaderModuleWGSLDescriptor::code`. +- `SetDeviceLostCallback`(deprecated by webgpu) has been removed in favor of `WGPUDeviceDescriptor::deviceLostCallback` member. +- `dawn::native::GetAdapter` (deprecated by dawn) has now been renamed to `dawn::native::EnumerateAdapters`. +- `wgpu::RenderBundleEncoder::colorFormatsCount` (deprecated by webgpu) has now been renamed to `colorFormatCount`. However, emscripten still uses the version of webgpu which shipped with `colorFormatsCount`, so in webassembly, `colorFormatsCount` continues to be used. We will change this after emscripten updates it's webgpu headers. diff --git a/IO/EnSight/vtkEnSight6BinaryReader.cxx b/IO/EnSight/vtkEnSight6BinaryReader.cxx index 2cd04c9755b..167e63efd41 100644 --- a/IO/EnSight/vtkEnSight6BinaryReader.cxx +++ b/IO/EnSight/vtkEnSight6BinaryReader.cxx @@ -31,6 +31,14 @@ // The BSDs use stat(). #define VTK_STAT_STRUCT struct stat #define VTK_STAT_FUNC stat +#elif defined __EMSCRIPTEN__ +#if defined _LARGEFILE64_SOURCE +#define VTK_STAT_STRUCT struct stat64 +#define VTK_STAT_FUNC stat64 +#else +#define VTK_STAT_STRUCT struct stat +#define VTK_STAT_FUNC stat +#endif #else // here, we're relying on _FILE_OFFSET_BITS defined in vtkWin32Header.h to help // us on POSIX without resorting to using stat64. diff --git a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx index e3c81bd5e8c..c374f9879bf 100644 --- a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx +++ b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx @@ -37,6 +37,14 @@ // The BSDs use stat(). #define VTK_STAT_STRUCT struct stat #define VTK_STAT_FUNC stat +#elif defined __EMSCRIPTEN__ +#if defined _LARGEFILE64_SOURCE +#define VTK_STAT_STRUCT struct stat64 +#define VTK_STAT_FUNC stat64 +#else +#define VTK_STAT_STRUCT struct stat +#define VTK_STAT_FUNC stat +#endif #else // here, we're relying on _FILE_OFFSET_BITS defined in vtkWin32Header.h to help // us on POSIX without resorting to using stat64. diff --git a/IO/ExportGL2PS/vtk.module b/IO/ExportGL2PS/vtk.module index d72b75b482e..97038c7fb17 100644 --- a/IO/ExportGL2PS/vtk.module +++ b/IO/ExportGL2PS/vtk.module @@ -3,7 +3,7 @@ NAME LIBRARY_NAME vtkIOExportGL2PS CONDITION - NOT ANDROID AND NOT APPLE_IOS AND NOT VTK_OPENGL_USE_GLES + NOT ANDROID AND NOT APPLE_IOS AND NOT EMSCRIPTEN AND NOT VTK_OPENGL_USE_GLES IMPLEMENTABLE IMPLEMENTS VTK::IOExportGL2PS diff --git a/IO/LSDyna/LSDynaFamily.cxx b/IO/LSDyna/LSDynaFamily.cxx index 15755d06840..fdb914ab6fa 100644 --- a/IO/LSDyna/LSDynaFamily.cxx +++ b/IO/LSDyna/LSDynaFamily.cxx @@ -24,8 +24,16 @@ namespace #if (VTK_SIZEOF_ID_TYPE == 8) && !defined(_DARWIN_FEATURE_64_BIT_INODE) && \ !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) #ifndef _WIN32 +#if defined __EMSCRIPTEN__ +#if defined _LARGEFILE64_SOURCE #define USE_STAT_64 #else +#define USE_STAT +#endif +#else +#define USE_STAT_64 +#endif +#else #define USE_WIN_STAT_64 #endif #else diff --git a/Rendering/WebGPU/vtkWGPUContext.cxx b/Rendering/WebGPU/vtkWGPUContext.cxx index d0400786707..b280022873a 100644 --- a/Rendering/WebGPU/vtkWGPUContext.cxx +++ b/Rendering/WebGPU/vtkWGPUContext.cxx @@ -73,7 +73,7 @@ static void WaitABit() } namespace vtkWGPUImpl = vtkWGPUEmscriptenImpl; -#elif VTK_USE_DAWN_NATIVE +#elif VTK_USE_DAWN_WEBGPU #include #include #include @@ -88,11 +88,11 @@ static struct struct { DawnProcTable ProcTable; - std::unique_ptr Instance = nullptr; + std::unique_ptr Instance = nullptr; } DawnNativeEntryPoint; struct { - dawn_native::Adapter Handle; + dawn::native::Adapter Handle; wgpu::BackendType DawnBackendType; struct { @@ -113,10 +113,10 @@ static void Initialize() } // Set up the native procs for the global proctable - GPUContext.DawnNativeEntryPoint.ProcTable = dawn_native::GetProcs(); + GPUContext.DawnNativeEntryPoint.ProcTable = dawn::native::GetProcs(); dawnProcSetProcs(&GPUContext.DawnNativeEntryPoint.ProcTable); GPUContext.DawnNativeEntryPoint.Instance = - std::unique_ptr(new dawn_native::Instance()); + std::unique_ptr(new dawn::native::Instance()); GPUContext.DawnNativeEntryPoint.Instance->DiscoverDefaultAdapters(); GPUContext.DawnNativeEntryPoint.Instance->EnableBackendValidation(true); @@ -125,16 +125,12 @@ static void Initialize() // are the preferred on their respective platforms, and Vulkan is preferred to // OpenGL GPUContext.Adapter.DawnBackendType = -#if defined(VTK_DAWN_ENABLE_BACKEND_D3D12) +#if defined(_WIN32) wgpu::BackendType::D3D12; -#elif defined(VTK_DAWN_ENABLE_BACKEND_METAL) +#elif defined(__APPLE__) wgpu::BackendType::Metal; -#elif defined(VTK_DAWN_ENABLE_BACKEND_VULKAN) - wgpu::BackendType::Vulkan; -#elif defined(VTK_DAWN_ENABLE_BACKEND_OPENGL) - wgpu::BackendType::OpenGL; #else -#error + wgpu::BackendType::Vulkan; #endif GPUContext.Adapter.Handle = nullptr; GPUContext.Initialized = true; @@ -159,48 +155,19 @@ static wgpu::Adapter RequestAdapter(const wgpu::RequestAdapterOptions& options) { Initialize(); - // Search available adapters for a good match, in the - // following priority order - std::vector typePriority; - if (options.powerPreference == wgpu::PowerPreference::LowPower) - { - // low power - typePriority = std::vector{ - wgpu::AdapterType::IntegratedGPU, - wgpu::AdapterType::DiscreteGPU, - wgpu::AdapterType::CPU, - }; - } - else if (options.powerPreference == wgpu::PowerPreference::HighPerformance) - { - // high performance - typePriority = std::vector{ - wgpu::AdapterType::DiscreteGPU, - wgpu::AdapterType::IntegratedGPU, - wgpu::AdapterType::CPU, - }; - } - - std::vector adapters = - GPUContext.DawnNativeEntryPoint.Instance->GetAdapters(); - for (auto reqType : typePriority) + std::vector adapters = + GPUContext.DawnNativeEntryPoint.Instance->EnumerateAdapters(&options); + for (const dawn::native::Adapter& adapter : adapters) { - for (const dawn_native::Adapter& adapter : adapters) - { - wgpu::AdapterProperties ap; - adapter.GetProperties(&ap); - if (ap.adapterType == reqType && - (reqType == wgpu::AdapterType::CPU || ap.backendType == GPUContext.Adapter.DawnBackendType)) - { - GPUContext.Adapter.Handle = adapter; - SetAdapterInfo(ap); - std::string msg = vtkfmt::format( - "Selected adapter {0} (device={1:#x} vendor={2:#x} type={3}/{4})", ap.name, ap.deviceID, - ap.vendorID, GPUContext.Adapter.Info.TypeName, GPUContext.Adapter.Info.BackendName); - vtkWGPUContextLog(msg); - return wgpu::Adapter(GPUContext.Adapter.Handle.Get()); - } - } + GPUContext.Adapter.Handle = adapter; + wgpu::AdapterProperties ap; + adapter.GetProperties(&ap); + SetAdapterInfo(ap); + std::string msg = vtkfmt::format( + "Selected adapter {0} (device={1:#x} vendor={2:#x} type={3}/{4})", ap.name, ap.deviceID, + ap.vendorID, GPUContext.Adapter.Info.TypeName, GPUContext.Adapter.Info.BackendName); + vtkWGPUContextLog(msg); + return wgpu::Adapter(GPUContext.Adapter.Handle.Get()); } return nullptr; @@ -234,7 +201,7 @@ static void LogAvailableAdapters() std::stringstream msg; msg << "Available adapters:\n"; - for (auto&& a : GPUContext.DawnNativeEntryPoint.Instance->GetAdapters()) + for (auto&& a : GPUContext.DawnNativeEntryPoint.Instance->EnumerateAdapters()) { wgpu::AdapterProperties p; a.GetProperties(&p); @@ -297,7 +264,7 @@ static const char* AdapterTypeName(wgpu::AdapterType t) } } namespace vtkWGPUImpl = vtkWGPUDawnImpl; -#endif // VTK_USE_DAWN_NATIVE +#endif // VTK_USE_DAWN_WEBGPU //------------------------------------------------------------------------------ void vtkWGPUContext::LogAvailableAdapters() diff --git a/Rendering/WebGPU/vtkWebGPUActor.cxx b/Rendering/WebGPU/vtkWebGPUActor.cxx index 4121547120e..63aa4d5ede1 100644 --- a/Rendering/WebGPU/vtkWebGPUActor.cxx +++ b/Rendering/WebGPU/vtkWebGPUActor.cxx @@ -79,7 +79,12 @@ wgpu::RenderBundle vtkWebGPUActor::RenderToBundle(vtkRenderer* ren, vtkMapper* m const int sampleCount = wgpuRenWin->GetMultiSamples() ? wgpuRenWin->GetMultiSamples() : 1; wgpu::RenderBundleEncoderDescriptor bundleEncDesc; +#if __EMSCRIPTEN__ + // FIXME: Update this after emscripten webgpu updates to colorFormatCount bundleEncDesc.colorFormatsCount = 1; +#else + bundleEncDesc.colorFormatCount = 1; +#endif bundleEncDesc.colorFormats = &colorFormat; bundleEncDesc.depthStencilFormat = wgpuRenWin->GetDepthStencilFormat(); bundleEncDesc.sampleCount = sampleCount; diff --git a/Rendering/WebGPU/vtkWebGPUInternalsShaderModule.cxx b/Rendering/WebGPU/vtkWebGPUInternalsShaderModule.cxx index 2d0731ac253..705fb9b59ac 100644 --- a/Rendering/WebGPU/vtkWebGPUInternalsShaderModule.cxx +++ b/Rendering/WebGPU/vtkWebGPUInternalsShaderModule.cxx @@ -8,7 +8,7 @@ wgpu::ShaderModule vtkWebGPUInternalsShaderModule::CreateFromWGSL( const wgpu::Device& device, const std::string& source) { wgpu::ShaderModuleWGSLDescriptor wgslDesc; - wgslDesc.source = source.c_str(); + wgslDesc.code = source.c_str(); wgpu::ShaderModuleDescriptor descriptor; descriptor.nextInChain = &wgslDesc; diff --git a/Rendering/WebGPU/vtkWebGPURenderWindow.cxx b/Rendering/WebGPU/vtkWebGPURenderWindow.cxx index f0e824f0e54..95a7d7fd605 100644 --- a/Rendering/WebGPU/vtkWebGPURenderWindow.cxx +++ b/Rendering/WebGPU/vtkWebGPURenderWindow.cxx @@ -61,8 +61,9 @@ void device_lost_callback(WGPUDeviceLostReason reason, char const* message, void default: reason_type_lbl = "Unknown"; } - vtkErrorWithObjectMacro(reinterpret_cast(self), - << "Device lost! Reason : " << message << " Reason Type: " << reason_type_lbl); + auto renWin = vtkRenderWindow::SafeDownCast(reinterpret_cast(self)); + vtkWarningWithObjectMacro( + renWin, << "Device lost! Reason : " << message << " Reason Type: " << reason_type_lbl); } struct PixelReadDescriptor @@ -136,6 +137,8 @@ bool vtkWebGPURenderWindow::WGPUInit() this->Adapter = vtkWGPUContext::RequestAdapter(options); wgpu::DeviceDescriptor deviceDescriptor = {}; deviceDescriptor.label = "vtkWebGPURenderWindow::WGPUInit"; + deviceDescriptor.deviceLostCallback = &device_lost_callback; + deviceDescriptor.deviceLostUserdata = this; ///@{ TODO: Populate feature requests // ... ///@} @@ -150,7 +153,6 @@ bool vtkWebGPURenderWindow::WGPUInit() } // install error handler this->Device.SetUncapturedErrorCallback(&::print_wgpu_error, this); - this->Device.SetDeviceLostCallback(&::device_lost_callback, this); ///@} return true; } @@ -161,7 +163,6 @@ void vtkWebGPURenderWindow::WGPUFinalize() vtkDebugMacro(<< __func__ << " WGPUInitialized=" << this->WGPUInitialized); this->DestroyDepthStencilTexture(); this->DestroySwapChain(); - this->Device.SetDeviceLostCallback(nullptr, nullptr); this->Device = nullptr; } @@ -586,18 +587,35 @@ void vtkWebGPURenderWindow::ReadPixels() this->BufferMapReadContext.src = this->ColorAttachment.OffscreenBuffer; this->BufferMapReadContext.size = this->ColorAttachment.OffscreenBuffer.GetSize(); this->BufferMapReadContext.dst = this->CachedPixelBytes; + this->BufferMapReadContext.window = this; auto onBufferMapped = [](WGPUBufferMapAsyncStatus status, void* userdata) { auto ctx = reinterpret_cast(userdata); switch (status) { - case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback: + case WGPUBufferMapAsyncStatus_ValidationError: + vtkErrorWithObjectMacro(ctx->window, << "Validation error occurred"); + break; + case WGPUBufferMapAsyncStatus_Unknown: + vtkErrorWithObjectMacro(ctx->window, << "Unknown error occurred"); + break; case WGPUBufferMapAsyncStatus_DeviceLost: - case WGPUBufferMapAsyncStatus_Error: + vtkErrorWithObjectMacro(ctx->window, << "Device lost!"); + break; + case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback: + vtkErrorWithObjectMacro(ctx->window, << "Buffer destroyed before callback"); + break; case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback: - case WGPUBufferMapAsyncStatus_Unknown: - default: - assert(false); + vtkErrorWithObjectMacro(ctx->window, << "Buffer unmapped before callback"); + break; + case WGPUBufferMapAsyncStatus_MappingAlreadyPending: + vtkErrorWithObjectMacro(ctx->window, << "Buffer already has a mapping pending completion"); + break; + case WGPUBufferMapAsyncStatus_OffsetOutOfRange: + vtkErrorWithObjectMacro(ctx->window, << "Buffer offset out of range"); + break; + case WGPUBufferMapAsyncStatus_SizeOutOfRange: + vtkErrorWithObjectMacro(ctx->window, << "Buffer size out of range"); break; case WGPUBufferMapAsyncStatus_Success: { @@ -611,6 +629,8 @@ void vtkWebGPURenderWindow::ReadPixels() std::copy(mapped, mapped + ctx->size, ctx->dst->GetPointer(0)); } break; + default: + break; } ctx->src.Unmap(); }; -- GitLab