diff --git a/wgpu/wgpu_entry.h b/wgpu/wgpu_entry.h index 56b144bf..75e52207 100644 --- a/wgpu/wgpu_entry.h +++ b/wgpu/wgpu_entry.h @@ -63,7 +63,6 @@ typedef struct { WGPUAdapter adapter; WGPUDevice device; WGPUSurface surface; - WGPUSwapChain swapchain; WGPUTextureFormat render_format; WGPUTexture msaa_tex; WGPUTexture depth_stencil_tex; @@ -88,6 +87,8 @@ void wgpu_mouse_wheel(wgpu_mouse_wheel_func fn); // internal functions, don't call void wgpu_swapchain_init(wgpu_state_t* state); void wgpu_swapchain_discard(wgpu_state_t* state); +void wgpu_swapchain_resized(wgpu_state_t* state); +WGPUTextureView wgpu_swapchain_next(wgpu_state_t* state); void wgpu_platform_start(wgpu_state_t* state); #ifdef __cplusplus diff --git a/wgpu/wgpu_entry_dawn.cc b/wgpu/wgpu_entry_dawn.cc index 9b952ec6..3ff4109c 100644 --- a/wgpu/wgpu_entry_dawn.cc +++ b/wgpu/wgpu_entry_dawn.cc @@ -1,7 +1,9 @@ //------------------------------------------------------------------------------ -// wgpu_entry_dawn.c +// wgpu_entry_dawn.cc // // Dawn-specific wgpu entry code. +// +// NOTE: we could use https://github.com/eliemichel/glfw3webgpu/ and avoid C++. //------------------------------------------------------------------------------ #include "GLFW/glfw3.h" #include "webgpu/webgpu_cpp.h" @@ -72,12 +74,31 @@ static void glfw_scroll_cb(GLFWwindow* window, double xoffset, double yoffset) { } } +static void glfw_resize_cb(GLFWwindow* window, int width, int height) { + wgpu_state_t* state = (wgpu_state_t*) glfwGetWindowUserPointer(window); + state->width = width; + state->height = height; + wgpu_swapchain_resized(state); +} + static void request_device_cb(WGPURequestDeviceStatus status, WGPUDevice device, const char* msg, void* userdata) { (void)status; (void)msg; (void)userdata; wgpu_state_t* state = (wgpu_state_t*) userdata; state->device = device; } +static void error_cb(WGPUErrorType type, const char* message, void* userdata) { + (void)type; (void)userdata; + if (type != WGPUErrorType_NoError) { + printf("ERROR: %s\n", message); + } +} + +static void logging_cb(WGPULoggingType type, const char* message, void* userdata) { + (void)type; (void)userdata; + printf("LOG: %s\n", message); +} + static void request_adapter_cb(WGPURequestAdapterStatus status, WGPUAdapter adapter, const char* msg, void* userdata) { (void)msg; wgpu_state_t* state = (wgpu_state_t*) userdata; @@ -92,23 +113,14 @@ static void request_adapter_cb(WGPURequestAdapterStatus status, WGPUAdapter adap WGPUDeviceDescriptor dev_desc = { .requiredFeatureCount = 1, .requiredFeatures = requiredFeatures, + .uncapturedErrorCallbackInfo = { + .callback = error_cb, + }, }; wgpuAdapterRequestDevice(adapter, &dev_desc, request_device_cb, userdata); assert(0 != state->device); } -static void error_cb(WGPUErrorType type, const char* message, void* userdata) { - (void)type; (void)userdata; - if (type != WGPUErrorType_NoError) { - printf("ERROR: %s\n", message); - } -} - -static void logging_cb(WGPULoggingType type, const char* message, void* userdata) { - (void)type; (void)userdata; - printf("LOG: %s\n", message); -} - void wgpu_platform_start(wgpu_state_t* state) { assert(state->instance == 0); @@ -117,9 +129,7 @@ void wgpu_platform_start(wgpu_state_t* state) { wgpuInstanceRequestAdapter(state->instance, 0, request_adapter_cb, state); assert(state->device); - wgpuDeviceSetUncapturedErrorCallback(state->device, error_cb, 0); wgpuDeviceSetLoggingCallback(state->device, logging_cb, 0); - wgpuDeviceSetDeviceLostCallback(state->device, 0, 0); wgpuDevicePushErrorScope(state->device, WGPUErrorFilter_Validation); glfwInit(); @@ -131,11 +141,11 @@ void wgpu_platform_start(wgpu_state_t* state) { glfwSetMouseButtonCallback(window, glfw_mousebutton_cb); glfwSetCursorPosCallback(window, glfw_cursorpos_cb); glfwSetScrollCallback(window, glfw_scroll_cb); + glfwSetWindowSizeCallback(window, glfw_resize_cb); state->surface = glfw_create_surface_for_window(state->instance, window); assert(state->surface); - // FIXME: Dawn doesn't support wgpuSurfaceGetPreferredFormat? - state->render_format = WGPUTextureFormat_BGRA8Unorm; + state->render_format = wgpuSurfaceGetPreferredFormat(state->surface, state->adapter); wgpu_swapchain_init(state); state->desc.init_cb(); @@ -145,11 +155,13 @@ void wgpu_platform_start(wgpu_state_t* state) { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); wgpuDevicePushErrorScope(state->device, WGPUErrorFilter_Validation); - state->swapchain_view = wgpuSwapChainGetCurrentTextureView(state->swapchain); - state->desc.frame_cb(); - wgpuSwapChainPresent(state->swapchain); - wgpuTextureViewRelease(state->swapchain_view); - state->swapchain_view = 0; + state->swapchain_view = wgpu_swapchain_next(state); + if (state->swapchain_view) { + state->desc.frame_cb(); + wgpuTextureViewRelease(state->swapchain_view); + state->swapchain_view = 0; + wgpuSurfacePresent(state->surface); + } wgpuDevicePopErrorScope(state->device, error_cb, 0); wgpuInstanceProcessEvents(state->instance); } diff --git a/wgpu/wgpu_entry_emsc.c b/wgpu/wgpu_entry_emsc.c index 38e2b89d..f0f12dd3 100644 --- a/wgpu/wgpu_entry_emsc.c +++ b/wgpu/wgpu_entry_emsc.c @@ -23,6 +23,7 @@ static EM_BOOL emsc_size_changed(int event_type, const EmscriptenUiEvent* ui_eve (void)event_type; (void)ui_event; wgpu_state_t* state = userdata; emsc_update_canvas_size(state); + wgpu_swapchain_resized(state); return true; } @@ -191,10 +192,12 @@ static EM_BOOL emsc_frame(double time, void* userdata) { return EM_TRUE; } wgpuDevicePushErrorScope(state->device, WGPUErrorFilter_Validation); - state->swapchain_view = wgpuSwapChainGetCurrentTextureView(state->swapchain); - state->desc.frame_cb(); - wgpuTextureViewRelease(state->swapchain_view); - state->swapchain_view = 0; + state->swapchain_view = wgpu_swapchain_next(state); + if (state->swapchain_view) { + state->desc.frame_cb(); + wgpuTextureViewRelease(state->swapchain_view); + state->swapchain_view = 0; + } wgpuDevicePopErrorScope(state->device, error_cb, 0); return EM_TRUE; } @@ -202,8 +205,12 @@ static EM_BOOL emsc_frame(double time, void* userdata) { void wgpu_platform_start(wgpu_state_t* state) { assert(state->instance == 0); + state->instance = wgpuCreateInstance(0); + assert(state->instance); + wgpuInstanceRequestAdapter(state->instance, 0, request_adapter_cb, state); + emsc_update_canvas_size(state); - emscripten_set_resize_callback("#canvas", 0, false, emsc_size_changed); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, state, false, emsc_size_changed); emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, state, true, emsc_keydown_cb); emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, state, true, emsc_keyup_cb); emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, state, true, emsc_keypress_cb); @@ -212,9 +219,5 @@ void wgpu_platform_start(wgpu_state_t* state) { emscripten_set_mousemove_callback("#canvas", state, true, emsc_mousemove_cb); emscripten_set_wheel_callback("#canvas", state, true, emsc_wheel_cb); - state->instance = wgpuCreateInstance(0); - assert(state->instance); - wgpuInstanceRequestAdapter(state->instance, 0, request_adapter_cb, state); - emscripten_request_animation_frame_loop(emsc_frame, state); } diff --git a/wgpu/wgpu_entry_swapchain.c b/wgpu/wgpu_entry_swapchain.c index e1291784..74686f04 100644 --- a/wgpu/wgpu_entry_swapchain.c +++ b/wgpu/wgpu_entry_swapchain.c @@ -5,26 +5,28 @@ //------------------------------------------------------------------------------ #include "wgpu_entry.h" #include +#include +#include void wgpu_swapchain_init(wgpu_state_t* state) { assert(state->adapter); assert(state->device); assert(state->surface); assert(state->render_format != WGPUTextureFormat_Undefined); - assert(0 == state->swapchain); assert(0 == state->depth_stencil_tex); assert(0 == state->depth_stencil_view); assert(0 == state->msaa_tex); assert(0 == state->msaa_view); - state->swapchain = wgpuDeviceCreateSwapChain(state->device, state->surface, &(WGPUSwapChainDescriptor){ - .usage = WGPUTextureUsage_RenderAttachment, + wgpuSurfaceConfigure(state->surface, &(WGPUSurfaceConfiguration){ + .device = state->device, .format = state->render_format, + .usage = WGPUTextureUsage_RenderAttachment, + .alphaMode = WGPUCompositeAlphaMode_Auto, .width = (uint32_t)state->width, .height = (uint32_t)state->height, .presentMode = WGPUPresentMode_Fifo, }); - assert(state->swapchain); if (!state->desc.no_depth_buffer) { state->depth_stencil_tex = wgpuDeviceCreateTexture(state->device, &(WGPUTextureDescriptor){ @@ -80,8 +82,38 @@ void wgpu_swapchain_discard(wgpu_state_t* state) { wgpuTextureRelease(state->depth_stencil_tex); state->depth_stencil_tex = 0; } - if (state->swapchain) { - wgpuSwapChainRelease(state->swapchain); - state->swapchain = 0; +} + +void wgpu_swapchain_resized(wgpu_state_t* state) { + wgpu_swapchain_discard(state); + wgpu_swapchain_init(state); +} + +// may return 0, in that case: skip this frame +WGPUTextureView wgpu_swapchain_next(wgpu_state_t* state) { + WGPUSurfaceTexture surface_texture = {0}; + wgpuSurfaceGetCurrentTexture(state->surface, &surface_texture); + switch (surface_texture.status) { + case WGPUSurfaceGetCurrentTextureStatus_Success: + // all ok + break; + case WGPUSurfaceGetCurrentTextureStatus_Timeout: + case WGPUSurfaceGetCurrentTextureStatus_Outdated: + case WGPUSurfaceGetCurrentTextureStatus_Lost: + // skip this frame and reconfigure surface + if (surface_texture.texture) { + wgpuTextureRelease(surface_texture.texture); + } + wgpu_swapchain_discard(state); + wgpu_swapchain_init(state); + return 0; + case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory: + case WGPUSurfaceGetCurrentTextureStatus_DeviceLost: + default: + printf("wgpuSurfaceGetCurrentTexture() failed with: %#.8x\n", surface_texture.status); + abort(); } + WGPUTextureView view = wgpuTextureCreateView(surface_texture.texture, 0); + wgpuTextureRelease(surface_texture.texture); + return view; }