diff --git a/src/backend/dx12/src/conv.rs b/src/backend/dx12/src/conv.rs index ed60129dc44..ceea67d2bbe 100644 --- a/src/backend/dx12/src/conv.rs +++ b/src/backend/dx12/src/conv.rs @@ -423,7 +423,7 @@ pub fn map_buffer_resource_state(access: buffer::Access) -> D3D12_RESOURCE_STATE let mut state = D3D12_RESOURCE_STATE_COMMON; if access.contains(buffer::TRANSFER_READ) { - state = state | D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_RESOLVE_DEST; + state = state | D3D12_RESOURCE_STATE_COPY_SOURCE; } if access.contains(buffer::INDEX_BUFFER_READ) { state = state | D3D12_RESOURCE_STATE_INDEX_BUFFER; @@ -472,7 +472,7 @@ pub fn map_image_resource_state(access: image::Access, layout: image::ImageLayou let mut state = D3D12_RESOURCE_STATE_COMMON; if access.contains(image::TRANSFER_READ) { - state = state | D3D12_RESOURCE_STATE_COPY_SOURCE | D3D12_RESOURCE_STATE_RESOLVE_DEST; + state = state | D3D12_RESOURCE_STATE_COPY_SOURCE; } if access.contains(image::INPUT_ATTACHMENT_READ) { state = state | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; diff --git a/src/backend/gl/src/window/glutin.rs b/src/backend/gl/src/window/glutin.rs index 157661252c4..518f2316894 100644 --- a/src/backend/gl/src/window/glutin.rs +++ b/src/backend/gl/src/window/glutin.rs @@ -143,7 +143,8 @@ pub fn config_context( pub struct Headless(pub glutin::HeadlessContext); -impl core::Instance for Headless { +impl core::Instance for Headless { + type Backend = B; fn enumerate_adapters(&self) -> Vec { unsafe { self.0.make_current().unwrap() }; let adapter = Adapter::new(|s| self.0.get_proc_address(s) as *const _); diff --git a/src/render/src/allocators/stack.rs b/src/render/src/allocators/stack.rs index b8356403572..8df1b8bfd35 100644 --- a/src/render/src/allocators/stack.rs +++ b/src/render/src/allocators/stack.rs @@ -68,7 +68,7 @@ impl Allocator for StackAllocator { device.mut_raw(), &buffer, usage); let memory_type = device.find_usage_memory(inner.usage, requirements.type_mask) .expect("could not find suitable memory"); - let mut stack = inner.stacks.entry(memory_type.id) + let stack = inner.stacks.entry(memory_type.id) .or_insert_with(|| ChunkStack::new(memory_type)); let (memory, offset, release) = stack.allocate( device, @@ -91,7 +91,7 @@ impl Allocator for StackAllocator { let requirements = device.mut_raw().get_image_requirements(&image); let memory_type = device.find_usage_memory(inner.usage, requirements.type_mask) .expect("could not find suitable memory"); - let mut stack = inner.stacks.entry(memory_type.id) + let stack = inner.stacks.entry(memory_type.id) .or_insert_with(|| ChunkStack::new(memory_type)); let (memory, offset, release) = stack.allocate( device, diff --git a/src/render/src/macros.rs b/src/render/src/macros.rs index 097f30fba9a..f1599b636d4 100644 --- a/src/render/src/macros.rs +++ b/src/render/src/macros.rs @@ -224,7 +224,7 @@ macro_rules! gfx_graphics_pipeline { preserves: &[], }; - device.create_renderpass_raw(&attachments[..], &[subpass], &[]) + device.create_render_pass_raw(&attachments[..], &[subpass], &[]) }; let mut pipeline_desc = cpso::GraphicsPipelineDesc::new( diff --git a/src/warden/Cargo.toml b/src/warden/Cargo.toml index 70944b5a22f..cbce76b78ee 100644 --- a/src/warden/Cargo.toml +++ b/src/warden/Cargo.toml @@ -18,6 +18,7 @@ path = "src/lib.rs" [features] default = [] +logger = ["env_logger"] vulkan = ["gfx-backend-vulkan"] dx12 = ["gfx-backend-dx12"] metal = ["gfx-backend-metal"] @@ -26,9 +27,10 @@ metal = ["gfx-backend-metal"] [dependencies] gfx-hal = { path = "../hal", version = "0.1", features = ["serialize"] } -#log = "0.3" +log = "0.3" ron = "0.1" serde = { version = "1.0", features = ["serde_derive"] } +env_logger = { version = "0.4", optional = true } [dependencies.gfx-backend-vulkan] path = "../../src/backend/vulkan" diff --git a/src/warden/README.md b/src/warden/README.md index 8783e369124..7bcb0aa2991 100644 --- a/src/warden/README.md +++ b/src/warden/README.md @@ -1,8 +1,8 @@ # Warden -Warden is the data-driver reference test framework for gfx-rs Hardware Abstraction Layer (gfx-hal), heavily inspired by the Wrench component of [WebRender](https://github.com/servo/webrender/). Warden's main purpose is to run a suite of GPU workloads on all native backends supported by the host platform, then match the results against provided expectations. Both the workloads and expectations are backend-agnostic. The backend discovery and initialization is done by the `reftest` binary. All that needs to be done by a developer is typing `make reftests` from the project root and ensuring that every test passes. +Warden is the data-driven reference test framework for gfx-rs Hardware Abstraction Layer (`gfx-hal`), heavily inspired by the Wrench component of [WebRender](https://github.com/servo/webrender/). Warden's main purpose is to run a suite of GPU workloads on all native backends supported by the host platform, then match the results against provided expectations. Both the workloads and expectations are backend-agnostic. The backend discovery and initialization is done by the `reftest` binary. All that needs to be done by a developer is typing `make reftests` from the project root and ensuring that every test passes. -Warden has two types of definitions: scene and suite. Both are written in [Ron](https://github.com/ron-rs/ron), but technically the code should work with any `serde`-enabled format given minimal tweaking. +Warden has two types of definitions: scene and suite. Both are written in [Ron](https://github.com/ron-rs/ron) format, but technically the code should work with any `serde`-enabled format given minimal tweaking. ## Scene definition @@ -12,12 +12,12 @@ A scene consists of a number of resources and jobs that can be run on them. Reso Internally, a scene has a command buffer to fill up all the initial data for resources. This command buffer needs to change the resource access and image layouts, so we establish a convention here by which every resource has an associated "stable" state that the user (and the reftest framework) promises to deliver at the end of each job. -For images with no source data, the stable layout is `ColorAttachmentOptimal` or `DepthStencilAttachmentOptimal` depending on the format. +For images with no source data, the stable layout is `ColorAttachmentOptimal` or `DepthStencilAttachmentOptimal` depending on the format. For sourced images, it's `ShaderReadOnlyOptimal`. ## Test suite -A test suite is just a set of scenes, each having a set of tests. A test is defined as a sequence of jobs being run on the scene and an expectation result. The central suite file can be found in [reftests](../../reftests/suite.ron). +A test suite is just a set of scenes, each with multiple tests. A test is defined as a sequence of jobs being run on the scene and an expectation result. The central suite file can be found in [reftests](../../reftests/suite.ron), and the serialization structures are in [reftest.rs](src/bin/reftest.rs). ## Warning -This gfx-rs component is heavy WIP, there is a lot of logic missing, especially with regards to error reporting. +This gfx-rs component is heavy WIP, provided under no warranty! There is a lot of logic missing, especially with regards to error reporting. diff --git a/src/warden/src/bin/reftest.rs b/src/warden/src/bin/reftest.rs index 65e44f198e5..1e5fd7115fd 100644 --- a/src/warden/src/bin/reftest.rs +++ b/src/warden/src/bin/reftest.rs @@ -6,6 +6,8 @@ extern crate ron; #[macro_use] extern crate serde; +#[cfg(feature = "logger")] +extern crate env_logger; #[cfg(feature = "vulkan")] extern crate gfx_backend_vulkan; #[cfg(feature = "dx12")] @@ -92,6 +94,9 @@ impl Harness { } fn main() { + #[cfg(feature = "logger")] + env_logger::init().unwrap(); + let harness = Harness::new("suite"); #[cfg(feature = "vulkan")] { @@ -101,7 +106,7 @@ fn main() { } #[cfg(feature = "dx12")] { - println!("Warding Dx12:"); + println!("Warding DX12:"); let instance = gfx_backend_dx12::Instance::create("warden", 1); harness.run(instance); } diff --git a/src/warden/src/gpu.rs b/src/warden/src/gpu.rs index cf4fe8b7a93..c43601b03aa 100644 --- a/src/warden/src/gpu.rs +++ b/src/warden/src/gpu.rs @@ -47,8 +47,9 @@ pub struct Image { pub handle: B::Image, #[allow(dead_code)] memory: B::Memory, - kind: hal::image::Kind, + kind: i::Kind, format: hal::format::Format, + stable_state: i::State, } pub struct RenderPass { @@ -90,6 +91,7 @@ fn align(x: usize, y: usize) -> usize { impl Scene { pub fn new(adapter: &B::Adapter, raw: &raw::Scene, data_path: &str) -> Self { + info!("creating Scene from {}", data_path); // initialize graphics let hal::Gpu { mut device, mut graphics_queues, memory_types, .. } = { let (ref family, queue_type) = adapter.get_queue_families()[0]; @@ -110,6 +112,9 @@ impl Scene { }) .unwrap() .clone(); + info!("upload memory: {:?}", upload_type); + info!("download memory: {:?}", &download_type); + let limits = device.get_limits().clone(); let queue = graphics_queues.remove(0); let mut command_pool = queue.create_graphics_pool( @@ -153,20 +158,39 @@ impl Scene { .unwrap(); let image = device.bind_image_memory(&memory, 0, unbound) .unwrap(); + let bits = format.0.describe_bits(); // process initial data for the image - if !data.is_empty() { + let stable_state = if data.is_empty() { + let (aspects, access, layout) = if bits.color != 0 { + (i::ASPECT_COLOR, i::COLOR_ATTACHMENT_WRITE, i::ImageLayout::ColorAttachmentOptimal) + } else { + (i::ASPECT_DEPTH | i::ASPECT_STENCIL, i::DEPTH_STENCIL_ATTACHMENT_WRITE, i::ImageLayout::DepthStencilAttachmentOptimal) + }; + if false { //TODO + let image_barrier = hal::memory::Barrier::Image { + states: (i::Access::empty(), i::ImageLayout::Undefined) .. (access, layout), + target: &image, + range: i::SubresourceRange { + aspects, + .. COLOR_RANGE.clone() + }, + }; + init_cmd.pipeline_barrier(hal::pso::TOP_OF_PIPE .. hal::pso::BOTTOM_OF_PIPE, &[image_barrier]); + } + (access, layout) + } else { // calculate required sizes let (w, h, d, aa) = kind.get_dimensions(); assert_eq!(aa, i::AaMode::Single); - let bpp = format.0.describe_bits().total as usize; - let width_bytes = bpp * w as usize / 8; + let width_bytes = bits.total as usize * w as usize / 8; let row_pitch = align(width_bytes, limits.min_buffer_copy_pitch_alignment); let upload_size = row_pitch as u64 * h as u64 * d as u64; // create upload buffer - let unbound_buffer = device.create_buffer(upload_size, bpp as _, hal::buffer::TRANSFER_SRC) + let unbound_buffer = device.create_buffer(upload_size, bits.total as _, hal::buffer::TRANSFER_SRC) .unwrap(); let upload_req = device.get_buffer_requirements(&unbound_buffer); + assert_ne!(upload_req.type_mask & (1< Scene { device.release_mapping_writer(mapping); } // add init commands + let final_state = (i::SHADER_READ, i::ImageLayout::ShaderReadOnlyOptimal); let image_barrier = hal::memory::Barrier::Image { states: (i::Access::empty(), i::ImageLayout::Undefined) .. (i::TRANSFER_WRITE, i::ImageLayout::TransferDstOptimal), target: &image, - range: COLOR_RANGE.clone(), + range: COLOR_RANGE.clone(), //TODO }; init_cmd.pipeline_barrier(hal::pso::TOP_OF_PIPE .. hal::pso::TRANSFER, &[image_barrier]); init_cmd.copy_buffer_to_image( @@ -213,21 +238,22 @@ impl Scene { }, }]); let image_barrier = hal::memory::Barrier::Image { - states: (i::TRANSFER_WRITE, i::ImageLayout::TransferDstOptimal) .. - (i::SHADER_READ, i::ImageLayout::ShaderReadOnlyOptimal), + states: (i::TRANSFER_WRITE, i::ImageLayout::TransferDstOptimal) .. final_state, target: &image, - range: COLOR_RANGE.clone(), + range: COLOR_RANGE.clone(), //TODO }; init_cmd.pipeline_barrier(hal::pso::TRANSFER .. hal::pso::BOTTOM_OF_PIPE, &[image_barrier]); // done upload_buffers.insert(name.clone(), (upload_buffer, upload_memory)); - } + final_state + }; resources.images.insert(name.clone(), Image { handle: image, memory, kind, format, + stable_state, }); } raw::Resource::RenderPass { ref attachments, ref subpasses, ref dependencies } => { @@ -385,6 +411,7 @@ impl Scene { } } raw::Job::Graphics { ref descriptors, ref framebuffer, ref pass, ref clear_values } => { + let _ = descriptors; //TODO let (ref fb, extent) = resources.framebuffers[framebuffer]; let rp = &resources.render_passes[&pass.0]; let rect = hal::target::Rect { @@ -419,10 +446,10 @@ impl Scene { let set = hal::pso::VertexBufferSet(buffers_raw); encoder.bind_vertex_buffers(set); } - Dc::BindPipeline(ref name) => { + Dc::BindPipeline(_) => { unimplemented!() } - Dc::BindDescriptorSets { ref layout, first, ref sets } => { + Dc::BindDescriptorSets { .. } => { //ref layout, first, ref sets unimplemented!() } Dc::Draw { ref vertices, ref instances } => { @@ -482,6 +509,7 @@ impl Scene { let unbound_buffer = self.device.create_buffer(down_size, bpp as _, hal::buffer::TRANSFER_DST) .unwrap(); let down_req = self.device.get_buffer_requirements(&unbound_buffer); + assert_ne!(down_req.type_mask & (1< Scene { let copy_submit = { let mut cmd_buffer = command_pool.acquire_command_buffer(); let image_barrier = hal::memory::Barrier::Image { - states: (i::SHADER_READ, i::ImageLayout::ShaderReadOnlyOptimal) .. - (i::TRANSFER_READ, i::ImageLayout::TransferSrcOptimal), + states: image.stable_state .. (i::TRANSFER_READ, i::ImageLayout::TransferSrcOptimal), target: &image.handle, - range: COLOR_RANGE.clone(), + range: COLOR_RANGE.clone(), //TODO }; cmd_buffer.pipeline_barrier(hal::pso::TOP_OF_PIPE .. hal::pso::TRANSFER, &[image_barrier]); cmd_buffer.copy_image_to_buffer( @@ -521,10 +548,9 @@ impl Scene { }, }]); let image_barrier = hal::memory::Barrier::Image { - states: (i::TRANSFER_READ, i::ImageLayout::TransferSrcOptimal) .. - (i::SHADER_READ, i::ImageLayout::ShaderReadOnlyOptimal), + states: (i::TRANSFER_READ, i::ImageLayout::TransferSrcOptimal) .. image.stable_state, target: &image.handle, - range: COLOR_RANGE.clone(), + range: COLOR_RANGE.clone(), //TODO }; cmd_buffer.pipeline_barrier(hal::pso::TRANSFER .. hal::pso::BOTTOM_OF_PIPE, &[image_barrier]); cmd_buffer.finish() diff --git a/src/warden/src/lib.rs b/src/warden/src/lib.rs index 1f301d23a26..fc16918a8a3 100644 --- a/src/warden/src/lib.rs +++ b/src/warden/src/lib.rs @@ -3,6 +3,8 @@ extern crate gfx_hal as hal; #[macro_use] +extern crate log; +#[macro_use] extern crate serde; pub mod gpu;