Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/canvas-c/src/webgpu/gpu_canvas_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1495,9 +1495,13 @@ pub unsafe extern "C" fn canvas_native_webgpu_context_present_surface(
if error.is_none() {
global.queue_submit(data.device.queue.queue.id, &[id]).ok();
}

global.command_buffer_drop(id);
}
Err(_) => {}
}

global.command_encoder_drop(encoder);
}
}
};
Expand Down
23 changes: 8 additions & 15 deletions crates/canvas-c/src/webgpu/gpu_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,21 @@ impl Drop for CanvasGPUTexture {
}
match self.surface_id {
Some(surface_id) => {
let global = self.instance.global();
let has_surface_presented = self
.has_surface_presented
.load(std::sync::atomic::Ordering::SeqCst);

// acquired but never presented: hand the image back to the swapchain
if !has_surface_presented {
let global = self.instance.global();

/*
match global.surface_texture_discard(surface_id) {
Ok(_) => {
self.surface_id = None;
}
Err(cause) => {
handle_error_fatal(
global,
cause,
"canvas_native_webgpu_texture_release",
)
},
if let Err(cause) = global.surface_texture_discard(surface_id) {
log::warn!("surface_texture_discard failed: {cause:?}");
}
*/
}

// drop the hub ref so the surface texture and its clear_view are freed
global.texture_drop(self.texture);
self.surface_id = None;
}
None => {
let context = self.instance.global();
Expand Down
2 changes: 2 additions & 0 deletions packages/canvas/WebGPU/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ export const native_ = Symbol('[[native]]');
export const mapState_ = Symbol('[[mapState]]');
export const contextPtr_ = Symbol('[[contextPtr]]');
export const adapter_ = Symbol('[[adapter]]');
// owning GPUCanvasContext stamped on the getCurrentTexture() texture (for release at present)
export const swapchainContext_ = Symbol('[[swapchainContext]]');
39 changes: 38 additions & 1 deletion packages/canvas/WebGPU/GPUCanvasContext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Helpers } from '../helpers';
import { adapter_, contextPtr_, GPUTextureUsage, native_ } from './Constants';
import { adapter_, contextPtr_, GPUTextureUsage, native_, swapchainContext_ } from './Constants';
import type { GPUDevice } from './GPUDevice';
import { GPUTexture } from './GPUTexture';
import type { GPUTextureView } from './GPUTextureView';
import type { GPUAdapter } from './GPUAdapter';
import type { GPUCanvasAlphaMode, GPUCanvasPresentMode, GPUExtent3D, GPUTextureFormat } from './Types';
import type { CanvasRenderingContext } from '../common';
Expand All @@ -18,6 +19,15 @@ export class GPUCanvasContext implements CanvasRenderingContext {
[native_] = null;
[contextPtr_] = null;

// per-frame swapchain views and textures, released at the next presentSurface()
private _swapchainViews: GPUTextureView[] = [];
private _swapchainTextures: GPUTexture[] = [];

/** @internal */
_registerSwapchainView(view: GPUTextureView) {
this._swapchainViews.push(view);
}

constructor(context: any, contextOptions: any = {}) {
let nativeContext = '0';
if (__ANDROID__) {
Expand Down Expand Up @@ -176,12 +186,39 @@ export class GPUCanvasContext implements CanvasRenderingContext {
const result = GPUTexture.fromNative(texture);
if (!result) {
console.error('GPUCanvasContext.getCurrentTexture: native texture wrapper contained no texture');
} else {
// mark as swapchain-owned and track for release at present
(result as any)[swapchainContext_] = this;
this._swapchainTextures.push(result);
}
return result;
}

presentSurface(_texture?: GPUTexture) {
this.native.presentSurface();
// release this frame's swapchain views and textures (their point of death)
const views = this._swapchainViews;
if (views.length > 0) {
this._swapchainViews = [];
for (let i = 0; i < views.length; i++) {
const view = views[i] as any;
view?.[native_]?.destroy?.();
if (view) {
view[native_] = null;
}
}
}
const texs = this._swapchainTextures;
if (texs.length > 0) {
this._swapchainTextures = [];
for (let i = 0; i < texs.length; i++) {
const tex = texs[i] as any;
tex?.[native_]?.__releaseHandle?.();
if (tex) {
tex[native_] = null;
}
}
}
}

getCapabilities(adapter: GPUAdapter): {
Expand Down
6 changes: 5 additions & 1 deletion packages/canvas/WebGPU/GPUCommandEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ export class GPUCommandEncoder {

finish(descriptor?: { label?: string }) {
const ret = this[native_].finish(descriptor);
return GPUCommandBuffer.fromNative(ret);
const buffer = GPUCommandBuffer.fromNative(ret);
// finish() consumes the encoder; release it now instead of waiting for GC
this[native_]?.destroy?.();
this[native_] = null;
return buffer;
}

insertDebugMarker(markerLabel: string) {
Expand Down
5 changes: 4 additions & 1 deletion packages/canvas/WebGPU/GPUComputePassEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export class GPUComputePassEncoder {
}

end() {
this[native_].end();
// end() consumes the pass; release it now instead of waiting for GC
const n = this[native_];
n?.end();
n?.destroy?.();
this[native_] = null;
}

Expand Down
8 changes: 8 additions & 0 deletions packages/canvas/WebGPU/GPUQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ export class GPUQueue {
return command[native_];
}),
);
// submit() consumes the command buffers; release them now instead of via GC
for (let i = 0; i < commands.length; i++) {
const command = commands[i] as any;
command?.[native_]?.destroy?.();
if (command) {
command[native_] = null;
}
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion packages/canvas/WebGPU/GPURenderPassEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ export class GPURenderPassEncoder {
}

end() {
this[native_].end();
// end() consumes the pass; release it now instead of waiting for GC
const n = this[native_];
n?.end();
n?.destroy?.();
this[native_] = null;
}

endOcclusionQuery() {
Expand Down
10 changes: 8 additions & 2 deletions packages/canvas/WebGPU/GPUTexture.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { native_ } from './Constants';
import { native_, swapchainContext_ } from './Constants';
import { GPUTextureView } from './GPUTextureView';
import type { GPUTextureViewDescriptor } from './Interfaces';

Expand Down Expand Up @@ -49,6 +49,12 @@ export class GPUTexture {

createView(desc?: GPUTextureViewDescriptor) {
const view = this[native_].createView(desc);
return GPUTextureView.fromNative(view);
const ret = GPUTextureView.fromNative(view);
// swapchain-texture views die at present; register them with the owning context
const ctx = (this as any)[swapchainContext_];
if (ret && ctx) {
ctx._registerSwapchainView(ret);
}
return ret;
}
}
37 changes: 37 additions & 0 deletions packages/canvas/platforms/ios/src/cpp/webgpu/ArcHandle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// ArcHandle.h — RAII owner for the Rust Arc handles exposed across the canvas C ABI.
//

#ifndef CANVAS_WEBGPU_ARCHANDLE_H
#define CANVAS_WEBGPU_ARCHANDLE_H

#include <memory>

// unique_ptr owner for a Rust Arc handle exposed across the C ABI. reset() runs the
// matching ..._release once and nulls the pointer; the GC finalizer's later drop is
// then a no-op. ArcHandle for const release fns, MutArcHandle for non-const.
template <typename T, void (*Release)(const T *)>
struct ArcDeleter {
void operator()(const T *ptr) const noexcept {
if (ptr != nullptr) {
Release(ptr);
}
}
};

template <typename T, void (*Release)(const T *)>
using ArcHandle = std::unique_ptr<const T, ArcDeleter<T, Release>>;

template <typename T, void (*Release)(T *)>
struct MutArcDeleter {
void operator()(T *ptr) const noexcept {
if (ptr != nullptr) {
Release(ptr);
}
}
};

template <typename T, void (*Release)(T *)>
using MutArcHandle = std::unique_ptr<T, MutArcDeleter<T, Release>>;

#endif // CANVAS_WEBGPU_ARCHANDLE_H
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
GPUAdapterImpl::GPUAdapterImpl(const CanvasGPUAdapter *adapter) : adapter_(adapter) {}

const CanvasGPUAdapter *GPUAdapterImpl::GetGPUAdapter() {
return this->adapter_;
return this->adapter_.get();
}


Expand Down
7 changes: 3 additions & 4 deletions packages/canvas/platforms/ios/src/cpp/webgpu/GPUAdapterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Common.h"
#include "Helpers.h"
#include "ObjectWrapperImpl.h"
#include "ArcHandle.h"
#include "GPUSupportedLimitsImpl.h"
#include "GPUDeviceImpl.h"
#include "GPUAdapterInfoImpl.h"
Expand All @@ -16,9 +17,7 @@ class GPUAdapterImpl : ObjectWrapperImpl {
public:
explicit GPUAdapterImpl(const CanvasGPUAdapter *adapter);

~GPUAdapterImpl() {
canvas_native_webgpu_adapter_release(this->GetGPUAdapter());
}
~GPUAdapterImpl() = default;

const CanvasGPUAdapter *GetGPUAdapter();

Expand Down Expand Up @@ -56,7 +55,7 @@ class GPUAdapterImpl : ObjectWrapperImpl {


private:
const CanvasGPUAdapter *adapter_;
ArcHandle<CanvasGPUAdapter, canvas_native_webgpu_adapter_release> adapter_;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
GPUAdapterInfoImpl::GPUAdapterInfoImpl(const CanvasGPUAdapterInfo *info) : info_(info) {}

const CanvasGPUAdapterInfo *GPUAdapterInfoImpl::GetInfo() {
return this->info_;
return this->info_.get();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
#include "Common.h"
#include "Helpers.h"
#include "ObjectWrapperImpl.h"
#include "ArcHandle.h"

class GPUAdapterInfoImpl : ObjectWrapperImpl {
public:
explicit GPUAdapterInfoImpl(const CanvasGPUAdapterInfo *info);

~GPUAdapterInfoImpl() {
canvas_native_webgpu_adapter_info_release(this->GetInfo());
}
~GPUAdapterInfoImpl() = default;

const CanvasGPUAdapterInfo *GetInfo();

Expand Down Expand Up @@ -51,7 +50,7 @@ class GPUAdapterInfoImpl : ObjectWrapperImpl {


private:
const CanvasGPUAdapterInfo *info_;
ArcHandle<CanvasGPUAdapterInfo, canvas_native_webgpu_adapter_info_release> info_;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GPUBindGroupImpl::GPUBindGroupImpl(const CanvasGPUBindGroup *groupLayout)
: group_(groupLayout) {}

const CanvasGPUBindGroup *GPUBindGroupImpl::GetBindGroup() {
return this->group_;
return this->group_.get();
}


Expand Down Expand Up @@ -63,7 +63,7 @@ GPUBindGroupImpl::GetLabel(v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value> &info) {
auto ptr = GetPointer(info.This());
if (ptr != nullptr) {
auto label = canvas_native_webgpu_bind_group_get_label(ptr->group_);
auto label = canvas_native_webgpu_bind_group_get_label(ptr->group_.get());
if (label == nullptr) {
info.GetReturnValue().SetEmptyString();
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
#include "Common.h"
#include "Helpers.h"
#include "ObjectWrapperImpl.h"
#include "ArcHandle.h"

class GPUBindGroupImpl : ObjectWrapperImpl {
public:
explicit GPUBindGroupImpl(const CanvasGPUBindGroup *group);

~GPUBindGroupImpl() {
canvas_native_webgpu_bind_group_release(this->GetBindGroup());
}
~GPUBindGroupImpl() = default;

const CanvasGPUBindGroup *GetBindGroup();

Expand All @@ -41,7 +40,7 @@ class GPUBindGroupImpl : ObjectWrapperImpl {
const v8::PropertyCallbackInfo<v8::Value> &info);

private:
const CanvasGPUBindGroup *group_;
ArcHandle<CanvasGPUBindGroup, canvas_native_webgpu_bind_group_release> group_;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GPUBindGroupLayoutImpl::GPUBindGroupLayoutImpl(const CanvasGPUBindGroupLayout *g
: groupLayout_(groupLayout) {}

const CanvasGPUBindGroupLayout *GPUBindGroupLayoutImpl::GetBindGroupLayout() {
return this->groupLayout_;
return this->groupLayout_.get();
}


Expand Down Expand Up @@ -63,7 +63,7 @@ GPUBindGroupLayoutImpl::GetLabel(v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value> &info) {
auto ptr = GetPointer(info.This());
if (ptr != nullptr) {
auto label = canvas_native_webgpu_bind_group_layout_get_label(ptr->groupLayout_);
auto label = canvas_native_webgpu_bind_group_layout_get_label(ptr->groupLayout_.get());
if (label == nullptr) {
info.GetReturnValue().SetEmptyString();
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
#include "Common.h"
#include "Helpers.h"
#include "ObjectWrapperImpl.h"
#include "ArcHandle.h"

class GPUBindGroupLayoutImpl : ObjectWrapperImpl {
public:
explicit GPUBindGroupLayoutImpl(const CanvasGPUBindGroupLayout *groupLayout);

~GPUBindGroupLayoutImpl() {
canvas_native_webgpu_bind_group_layout_release(this->GetBindGroupLayout());
}
~GPUBindGroupLayoutImpl() = default;

const CanvasGPUBindGroupLayout *GetBindGroupLayout();

Expand All @@ -41,7 +40,7 @@ class GPUBindGroupLayoutImpl : ObjectWrapperImpl {
const v8::PropertyCallbackInfo<v8::Value> &info);

private:
const CanvasGPUBindGroupLayout *groupLayout_;
ArcHandle<CanvasGPUBindGroupLayout, canvas_native_webgpu_bind_group_layout_release> groupLayout_;
};


Expand Down
Loading