use crate::*;
use crate::d3d9::*;
use winapi::ctypes::c_void;
use winapi::shared::d3d9::{IDirect3DIndexBuffer9, IDirect3DVertexBuffer9, IDirect3DResource9};
use winapi::um::unknwnbase::IUnknown;
use std::ptr::null_mut;
#[derive(Clone)] #[repr(transparent)]
pub struct IndexBuffer(pub(crate) mcom::Rc<IDirect3DIndexBuffer9>);
#[derive(Clone)] #[repr(transparent)]
pub struct VertexBuffer(pub(crate) mcom::Rc<IDirect3DVertexBuffer9>);
unsafe impl AsSafe<IUnknown > for IndexBuffer { fn as_safe(&self) -> &IUnknown { &***self.0 } }
unsafe impl AsSafe<IDirect3DResource9 > for IndexBuffer { fn as_safe(&self) -> &IDirect3DResource9 { &**self.0 } }
unsafe impl AsSafe<IDirect3DIndexBuffer9 > for IndexBuffer { fn as_safe(&self) -> &IDirect3DIndexBuffer9 { &*self.0 } }
unsafe impl AsSafe<IUnknown > for VertexBuffer { fn as_safe(&self) -> &IUnknown { &***self.0 } }
unsafe impl AsSafe<IDirect3DResource9 > for VertexBuffer { fn as_safe(&self) -> &IDirect3DResource9 { &**self.0 } }
unsafe impl AsSafe<IDirect3DVertexBuffer9 > for VertexBuffer { fn as_safe(&self) -> &IDirect3DVertexBuffer9 { &*self.0 } }
pub trait IDirect3DIndexBuffer9Ext : AsSafe<IDirect3DIndexBuffer9> {
fn get_desc(&self) -> Result<IndexBufferDesc, MethodError> {
let mut desc = IndexBufferDesc::default();
let hr = unsafe { self.as_winapi().GetDesc(&mut *desc) };
MethodError::check("IDirect3DIndexBuffer9::GetDesc", hr)?;
Ok(desc)
}
unsafe fn lock_unchecked(&self, offset: u32, size: u32, flags: impl Into<Lock>) -> Result<*mut c_void, MethodError> {
let mut data = null_mut();
let hr = self.as_winapi().Lock(offset, size, &mut data, flags.into().into());
MethodError::check("IDirect3DIndexBuffer9::Lock", hr)?;
Ok(data)
}
fn unlock(&self) -> Result<(), MethodError> {
let hr = unsafe { self.as_winapi().Unlock() };
MethodError::check("IDirect3DIndexBuffer9::Unlock", hr)
}
}
impl<T: AsSafe<IDirect3DIndexBuffer9>> IDirect3DIndexBuffer9Ext for T {}
pub trait IDirect3DVertexBuffer9Ext : AsSafe<IDirect3DVertexBuffer9> {
fn get_desc(&self) -> Result<VertexBufferDesc, MethodError> {
let mut desc = VertexBufferDesc::default();
let hr = unsafe { self.as_winapi().GetDesc(&mut *desc) };
MethodError::check("IDirect3DVertexBuffer9::GetDesc", hr)?;
Ok(desc)
}
unsafe fn lock_unchecked(&self, offset: u32, size: u32, flags: impl Into<Lock>) -> Result<*mut c_void, MethodError> {
let mut data = null_mut();
let hr = self.as_winapi().Lock(offset, size, &mut data, flags.into().into());
MethodError::check("IDirect3DVertexBuffer9::Lock", hr)?;
Ok(data)
}
fn unlock(&self) -> Result<(), MethodError> {
let hr = unsafe { self.as_winapi().Unlock() };
MethodError::check("IDirect3DVertexBuffer9::Unlock", hr)
}
}
impl<T: AsSafe<IDirect3DVertexBuffer9>> IDirect3DVertexBuffer9Ext for T {}
#[cfg(test)] mod tests {
use dev::d3d9::*;
#[test] fn index_buffer() {
let device = device_pure();
let tri16 = device.create_index_buffer(3*2, Usage::None, Format::Index16, Pool::Default, ()).unwrap(); let odd16 = device.create_index_buffer(3*3, Usage::None, Format::Index16, Pool::Default, ()).unwrap(); let tri32 = device.create_index_buffer(3*4, Usage::None, Format::Index32, Pool::Default, ()).unwrap();
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(0, Usage::None, Format::Index16, Pool::Default, ()).err(), "empty");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1, Usage::None, Format::Index16, Pool::Default, ()).err(), "too small for 16-bit IndexBuffer");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(3, Usage::None, Format::Index32, Pool::Default, ()).err(), "too small for 32-bit IndexBuffer");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1000, Invalid, Format::Index16, Pool::Default, ()).err(), "invalid usage");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1000, Usage::None, Format::Unknown, Pool::Default, ()).err(), "bad format");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1000, Usage::None, Format::X8B8G8R8, Pool::Default, ()).err(), "bad format");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1000, Usage::None, Invalid, Pool::Default, ()).err(), "bad format");
assert_eq!(D3DERR::INVALIDCALL, device.create_index_buffer(1000, Usage::None, Format::Index16, Invalid, ()).err(), "bad pool");
assert!(device.get_indices().unwrap().is_none());
device.set_indices(&tri16).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), tri16.as_raw());
device.set_indices(Some(&tri16)).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), tri16.as_raw());
device.set_indices(&odd16).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), odd16.as_raw());
device.set_indices(Some(&odd16)).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), odd16.as_raw());
device.set_indices(&tri32).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), tri32.as_raw());
device.set_indices(Some(&tri32)).unwrap();
assert_eq!(device.get_indices().unwrap().unwrap().as_raw(), tri32.as_raw());
device.set_indices(None).unwrap();
assert!(device.get_indices().unwrap().is_none());
}
#[test] fn create_vertex_buffer() {
let device = device_pure();
let _trixyz = device.create_vertex_buffer(3*4*3, Usage::None, FVF::None, Pool::Default, ()).unwrap(); let _quadxyz= device.create_vertex_buffer(4*4*3, Usage::None, FVF::None, Pool::Default, ()).unwrap(); let _trixyz = device.create_vertex_buffer(3*4*3, Usage::None, FVF::XYZ, Pool::Default, ()).unwrap(); let _quadxyz= device.create_vertex_buffer(4*4*3, Usage::None, FVF::XYZ, Pool::Default, ()).unwrap();
let _one = device.create_vertex_buffer(1, Usage::None, FVF::None, Pool::Default, ()).unwrap();
assert_eq!(D3DERR::INVALIDCALL, device.create_vertex_buffer(1, Usage::None, FVF::XYZ, Pool::Default, ()).err());
assert_eq!(D3DERR::INVALIDCALL, device.create_vertex_buffer(0, Usage::None, FVF::XYZ, Pool::Default, ()).err(), "empty");
assert_eq!(D3DERR::INVALIDCALL, device.create_vertex_buffer(1000, Invalid, FVF::XYZ, Pool::Default, ()).err(), "invalid usage");
let _badfmt = device.create_vertex_buffer(1000, Usage::None, Invalid, Pool::Default, ()).unwrap(); assert_eq!(D3DERR::INVALIDCALL, device.create_vertex_buffer(1000, Usage::None, FVF::XYZ, Invalid, ()).err(), "bad pool");
}
#[test] fn overflow_allocs() {
if testfast() { return; }
fn index_loop_alloc_size(alloc: u32) -> Result<(), MethodError> {
let device = device_pure();
let mut ibs = Vec::new();
for _n in 0..1000 { ibs.push(device.create_index_buffer(alloc, Usage::None, Format::Index16, Pool::Default, ())?); }
panic!("expected overflow_allocs::index_loop_alloc_size(0x{:08x}) to fail before collecting 1000 allocs", alloc);
}
fn vertex_loop_alloc_size(alloc: u32) -> Result<(), MethodError> {
let device = device_pure();
let mut vbs = Vec::new();
for _n in 0..1000 { vbs.push(device.create_vertex_buffer(alloc, Usage::None, FVF::None, Pool::Default, ())?); }
panic!("expected overflow_allocs::vertex_loop_alloc_size(0x{:08x}) to fail before collecting 1000 allocs", alloc);
}
for n in [
!0,
!0-4,
!0-100,
super::MAX_BUFFER_ALLOC,
0xF000_0000,
!0/2,
!0/8,
].iter().copied() {
match index_loop_alloc_size(n).unwrap_err().kind() {
E::OUTOFMEMORY => {}, D3DERR::OUTOFVIDEOMEMORY => {}, THINERR::ALLOC_OVERFLOW => {}, other => panic!("index_loop_alloc_size(0x{:08x}), expected a different kind of error, got: {}", n, other),
}
match vertex_loop_alloc_size(n).unwrap_err().kind() {
E::OUTOFMEMORY => {}, D3DERR::OUTOFVIDEOMEMORY => {}, THINERR::ALLOC_OVERFLOW => {}, other => panic!("vertex_loop_alloc_size(0x{:08x}), expected a different kind of error, got: {}", n, other),
}
}
}
}