use crate::{
error::{QuantRS2Error, QuantRS2Result},
qubit::QubitId,
};
use scirs2_core::ndarray::Array2;
use scirs2_core::Complex64;
use super::{GpuBackend, GpuBuffer, GpuKernel};
#[inline(always)]
fn vulkan_unavailable(context: &str) -> QuantRS2Error {
QuantRS2Error::UnsupportedOperation(format!(
"Vulkan backend not available in this build: {context}. \
Enable the `vulkan` feature and ensure the Vulkan loader (libvulkan) is installed \
with a compatible GPU driver."
))
}
pub struct VulkanBuffer {
size_elements: usize,
}
impl GpuBuffer for VulkanBuffer {
fn size(&self) -> usize {
self.size_elements * std::mem::size_of::<Complex64>()
}
fn upload(&mut self, _data: &[Complex64]) -> QuantRS2Result<()> {
Err(vulkan_unavailable("upload via vkMapMemory/vkCmdCopyBuffer"))
}
fn download(&self, _data: &mut [Complex64]) -> QuantRS2Result<()> {
Err(vulkan_unavailable(
"download via vkMapMemory/vkCmdCopyBuffer",
))
}
fn sync(&self) -> QuantRS2Result<()> {
Err(vulkan_unavailable(
"vkQueueWaitIdle / fence synchronization",
))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
pub struct VulkanKernel;
impl GpuKernel for VulkanKernel {
fn apply_single_qubit_gate(
&self,
_state: &mut dyn GpuBuffer,
_gate_matrix: &[Complex64; 4],
_qubit: QubitId,
_n_qubits: usize,
) -> QuantRS2Result<()> {
Err(vulkan_unavailable("apply_single_qubit_gate compute shader"))
}
fn apply_two_qubit_gate(
&self,
_state: &mut dyn GpuBuffer,
_gate_matrix: &[Complex64; 16],
_control: QubitId,
_target: QubitId,
_n_qubits: usize,
) -> QuantRS2Result<()> {
Err(vulkan_unavailable("apply_two_qubit_gate compute shader"))
}
fn apply_multi_qubit_gate(
&self,
_state: &mut dyn GpuBuffer,
_gate_matrix: &Array2<Complex64>,
_qubits: &[QubitId],
_n_qubits: usize,
) -> QuantRS2Result<()> {
Err(vulkan_unavailable("apply_multi_qubit_gate compute shader"))
}
fn measure_qubit(
&self,
_state: &dyn GpuBuffer,
_qubit: QubitId,
_n_qubits: usize,
) -> QuantRS2Result<(bool, f64)> {
Err(vulkan_unavailable("measure_qubit reduction kernel"))
}
fn expectation_value(
&self,
_state: &dyn GpuBuffer,
_observable: &Array2<Complex64>,
_qubits: &[QubitId],
_n_qubits: usize,
) -> QuantRS2Result<f64> {
Err(vulkan_unavailable("expectation_value reduction kernel"))
}
}
pub struct VulkanBackend {
kernel: VulkanKernel,
}
impl VulkanBackend {
pub fn new() -> QuantRS2Result<Self> {
eprintln!(
"[quantrs2-core] WARNING: Vulkan backend requested but Vulkan runtime is not available. \
This backend requires the Vulkan loader (libvulkan) and a compatible GPU driver. \
Enable the `vulkan` feature and install the appropriate driver."
);
Err(QuantRS2Error::UnsupportedOperation(
"Vulkan backend not available in this build. \
Compile with the `vulkan` feature and ensure the Vulkan loader is installed."
.to_string(),
))
}
}
impl GpuBackend for VulkanBackend {
fn is_available() -> bool {
false
}
fn name(&self) -> &'static str {
"Vulkan"
}
fn device_info(&self) -> String {
"Vulkan backend (stub — no runtime available)".to_string()
}
fn allocate_state_vector(&self, n_qubits: usize) -> QuantRS2Result<Box<dyn GpuBuffer>> {
eprintln!(
"[quantrs2-core] WARNING: VulkanBackend::allocate_state_vector called for {n_qubits} qubits \
but Vulkan runtime is not available."
);
Err(vulkan_unavailable(&format!(
"allocate_state_vector for {n_qubits} qubits"
)))
}
fn allocate_density_matrix(&self, n_qubits: usize) -> QuantRS2Result<Box<dyn GpuBuffer>> {
eprintln!(
"[quantrs2-core] WARNING: VulkanBackend::allocate_density_matrix called for {n_qubits} qubits \
but Vulkan runtime is not available."
);
Err(vulkan_unavailable(&format!(
"allocate_density_matrix for {n_qubits} qubits"
)))
}
fn kernel(&self) -> &dyn GpuKernel {
&self.kernel
}
}