Я создаю собственный плагин Unity в Rust.
Поскольку мне нужно было получить ID3D11Texture2D в Rust, я решил использовать крейт windows-rs версии 0.56.0.
Код единства
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class DesktopCapture : MonoBehaviour
{
[DllImport("texture2d_user", EntryPoint = "modify_texture")]
static extern void ModifyTexture(IntPtr texptr);
void Start()
{
var tex = Texture2D.normalTexture;
ModifyTexture(tex.GetNativeTexturePtr());
}
}
Кодекс ржавчины
use windows::core::IUnknown;
use windows::Win32::Graphics::Direct3D11::*;
#[no_mangle]
pub extern "C" fn modify_texture(texptr: *mut IUnknown) {
let texture: *mut ID3D11Texture2D = texptr.cast::<ID3D11Texture2D>();
let dimension: D3D11_RESOURCE_DIMENSION = unsafe { (*texture).GetType() };
()
}
Хотя передача аргументов прошла гладко, вызов метода GetType для ID3D11Texture2D привел к ошибке сегментации.
Я хотел бы знать, как решить эту проблему. Заранее спасибо за вашу помощь.
Чтобы определить, связана ли проблема с Unity или Rust, я создал собственный плагин на C++ и использовал его для создания ID3D11Texture2D. Методы вызывались без проблем, так что я считаю, что проблема не в Unity.
Журнал редактора Unity
Received signal SIGSEGV
Obtained 26 stack frames
0x00007ffadcdc1020 (texture2d_user) texture2d_user::modify_texture (at C:/Users/sabro/source/testproject/texture2d_user/src/lib.rs:8)
0x000001ce154eb96a (Mono JIT Code) (wrapper managed-to-native) DesktopCapture:ModifyTexture (intptr)
0x000001ce154eb573 (Mono JIT Code) DesktopCapture:Start () (at C:/Users/sabro/source/testproject/DesktopCapture/Assets/DesktopCapture.cs:17)
0x000001cdef27a488 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007ffadf74e274 (mono-2.0-bdwgc) mono_jit_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/mini/mini-runtime.c:3445)
0x00007ffadf68eb74 (mono-2.0-bdwgc) do_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3066)
0x00007ffadf68ed0c (mono-2.0-bdwgc) mono_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3113)
0x00007ff78895a824 (Unity) scripting_method_invoke
0x00007ff788938944 (Unity) ScriptingInvocation::Invoke
0x00007ff78892715b (Unity) MonoBehaviour::InvokeMethodOrCoroutineChecked
0x00007ff788927266 (Unity) MonoBehaviour::InvokeMethodOrCoroutineChecked
0x00007ff7889212c2 (Unity) MonoBehaviour::DelayedStartCall
0x00007ff7883c2aa4 (Unity) DelayedCallManager::Update
0x00007ff7885f2c59 (Unity) `InitPlayerLoopCallbacks'::`2'::EarlyUpdateScriptRunDelayedStartupFrameRegistrator::Forward
0x00007ff7885d291c (Unity) ExecutePlayerLoop
0x00007ff7885d2a98 (Unity) ExecutePlayerLoop
0x00007ff7885d9375 (Unity) PlayerLoop
0x00007ff78959cd2f (Unity) PlayerLoopController::InternalUpdateScene
0x00007ff789594513 (Unity) PlayerLoopController::EnterPlayMode
0x00007ff7895a4887 (Unity) PlayerLoopController::SetIsPlaying
0x00007ff7895a7f50 (Unity) Application::TickTimer
0x00007ff789a1e51a (Unity) MainMessageLoop
0x00007ff789a23d80 (Unity) WinMain
0x00007ff78ae07fee (Unity) __scrt_common_main_seh
0x00007ffbd02e7344 (KERNEL32) BaseThreadInitThunk
0x00007ffbd04226b1 (ntdll) RtlUserThreadStart





Похоже, ваш .cast() вызывает <*mut T>::cast , а не <IUnknown as Interface>::cast. Первое — это просто прямое приведение указателя, а второе — через QueryInterface. Плюс в том, что Interface::cast возвращает Result<T>, но ваш код напрямую присваивает результат переменной *mut ID3D11Texture2D. Interface::cast даже не имеет права вызываться, потому что для этого требуется &self, но вы вызываете .cast() по необработанному указателю.
В крейте windows тип интерфейса, такой как IUnknown, на самом деле уже является указателем: то, что мы пишем IUnknown* на C или C++, мы пишем просто IUnknown на Rust. В ваших функциях Rust, которые вызываются через FFI, параметры вашего интерфейса должны быть напечатаны *mut c_void, затем вы можете привести их к типу интерфейса, используя Interface::from_raw_borrowed . (Не используйте Interface::from_raw здесь: возвращаемое значение вызовет Release() при его удалении, но ваша функция не выполнила соответствующие AddRef() или QueryInterface().)
use std::ffi::c_void;
use windows::core::IUnknown;
use windows::Win32::Graphics::Direct3D11::*;
#[no_mangle]
pub extern "C" fn modify_texture(texptr: *mut c_void) {
let texptr = unsafe { IUnknown::from_raw_borrowed(&texptr).expect("got a null texture pointer") };
let texture: ID3D11Texture2D = texptr.cast::<ID3D11Texture2D>().expect("object doesn't implement ID3D11Texture2D");
let dimension: D3D11_RESOURCE_DIMENSION = unsafe { texture.GetType() };
}