Add renderer texture copy command
This commit is contained in:
@@ -84,6 +84,7 @@ using pp::renderer::validate_scissor;
|
||||
using pp::renderer::validate_shader_catalog;
|
||||
using pp::renderer::validate_shader_program_desc;
|
||||
using pp::renderer::validate_shader_uniform_write;
|
||||
using pp::renderer::validate_texture_copy_descs;
|
||||
using pp::renderer::validate_texture_slot;
|
||||
using pp::renderer::validate_viewport;
|
||||
|
||||
@@ -380,6 +381,36 @@ public:
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status copy_texture(
|
||||
pp::renderer::ITexture2D& source,
|
||||
ReadbackRegion source_region,
|
||||
pp::renderer::ITexture2D& destination,
|
||||
ReadbackRegion destination_region) noexcept override
|
||||
{
|
||||
const auto status = validate_texture_copy_descs(
|
||||
source.desc(),
|
||||
source_region,
|
||||
destination.desc(),
|
||||
destination_region);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
const auto source_bytes = readback_byte_size(source.desc(), source_region);
|
||||
if (!source_bytes.ok()) {
|
||||
return source_bytes.status();
|
||||
}
|
||||
|
||||
const auto destination_bytes = readback_byte_size(destination.desc(), destination_region);
|
||||
if (!destination_bytes.ok()) {
|
||||
return destination_bytes.status();
|
||||
}
|
||||
|
||||
last_copy_source_bytes = source_bytes.value();
|
||||
last_copy_destination_bytes = destination_bytes.value();
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status capture_frame(
|
||||
IRenderTarget& target,
|
||||
pp::renderer::IReadbackBuffer& destination) noexcept override
|
||||
@@ -450,6 +481,8 @@ public:
|
||||
std::uint32_t last_sampler_slot = 0;
|
||||
SamplerDesc last_sampler_desc {};
|
||||
std::uint64_t last_upload_bytes = 0;
|
||||
std::uint64_t last_copy_source_bytes = 0;
|
||||
std::uint64_t last_copy_destination_bytes = 0;
|
||||
std::uint64_t last_readback_bytes = 0;
|
||||
std::uint64_t last_capture_bytes = 0;
|
||||
std::uint64_t last_blit_source_bytes = 0;
|
||||
@@ -698,6 +731,48 @@ void validates_blit_contract(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, blit_filter_name(static_cast<BlitFilter>(255)) == std::string_view("unknown"));
|
||||
}
|
||||
|
||||
void validates_texture_copy_contract(pp::tests::Harness& h)
|
||||
{
|
||||
const TextureDesc rgba_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
};
|
||||
const TextureDesc r8_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::r8,
|
||||
};
|
||||
|
||||
PP_EXPECT(h, validate_texture_copy_descs(
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 1, .y = 2, .width = 4, .height = 3 },
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 5, .y = 4, .width = 4, .height = 3 })
|
||||
.ok());
|
||||
|
||||
const auto mismatched_format = validate_texture_copy_descs(
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
r8_desc,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
const auto mismatched_region = validate_texture_copy_descs(
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 2, .height = 1 },
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
const auto outside_source = validate_texture_copy_descs(
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 15, .y = 0, .width = 2, .height = 1 },
|
||||
rgba_desc,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 2, .height = 1 });
|
||||
|
||||
PP_EXPECT(h, !mismatched_format.ok());
|
||||
PP_EXPECT(h, mismatched_format.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !mismatched_region.ok());
|
||||
PP_EXPECT(h, mismatched_region.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !outside_source.ok());
|
||||
PP_EXPECT(h, outside_source.code == StatusCode::out_of_range);
|
||||
}
|
||||
|
||||
void validates_blend_contract(pp::tests::Harness& h)
|
||||
{
|
||||
const BlendState alpha_blend {
|
||||
@@ -1105,6 +1180,12 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
||||
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
||||
upload_bytes)
|
||||
.ok());
|
||||
PP_EXPECT(h, context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 4, .height = 5 })
|
||||
.ok());
|
||||
PP_EXPECT(h, context.read_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
||||
@@ -1141,6 +1222,8 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, device.context.last_sampler_desc.mag_filter == SamplerFilter::nearest);
|
||||
PP_EXPECT(h, device.context.last_sampler_desc.address_u == SamplerAddressMode::repeat);
|
||||
PP_EXPECT(h, device.context.last_upload_bytes == 80U);
|
||||
PP_EXPECT(h, device.context.last_copy_source_bytes == 80U);
|
||||
PP_EXPECT(h, device.context.last_copy_destination_bytes == 80U);
|
||||
PP_EXPECT(h, device.context.last_readback_bytes == 80U);
|
||||
PP_EXPECT(h, device.context.last_capture_bytes == 8192U);
|
||||
PP_EXPECT(h, device.context.last_blit_source_bytes == 80U);
|
||||
@@ -1390,28 +1473,43 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, commands_after_upload[12].upload_bytes == 96U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_upload[12].kind) == std::string_view("upload_texture"));
|
||||
|
||||
PP_EXPECT(h, context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 4, .y = 5, .width = 8, .height = 3 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 8, .height = 3 })
|
||||
.ok());
|
||||
const auto commands_after_copy = device.commands();
|
||||
PP_EXPECT(h, commands_after_copy.size() == 14U);
|
||||
PP_EXPECT(h, commands_after_copy[13].kind == RecordedRenderCommandKind::copy_texture);
|
||||
PP_EXPECT(h, commands_after_copy[13].source_region.x == 4U);
|
||||
PP_EXPECT(h, commands_after_copy[13].destination_region.x == 0U);
|
||||
PP_EXPECT(h, commands_after_copy[13].copy_source_bytes == 96U);
|
||||
PP_EXPECT(h, commands_after_copy[13].copy_destination_bytes == 96U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_copy[13].kind) == std::string_view("copy_texture"));
|
||||
|
||||
PP_EXPECT(h, context.read_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 4, .y = 5, .width = 8, .height = 3 },
|
||||
readback_buffer)
|
||||
.ok());
|
||||
const auto commands_after_readback = device.commands();
|
||||
PP_EXPECT(h, commands_after_readback.size() == 14U);
|
||||
PP_EXPECT(h, commands_after_readback[13].kind == RecordedRenderCommandKind::read_texture);
|
||||
PP_EXPECT(h, commands_after_readback[13].texture_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_readback[13].readback_region.x == 4U);
|
||||
PP_EXPECT(h, commands_after_readback[13].readback_region.height == 3U);
|
||||
PP_EXPECT(h, commands_after_readback[13].readback_bytes == 96U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[13].kind) == std::string_view("read_texture"));
|
||||
PP_EXPECT(h, commands_after_readback.size() == 15U);
|
||||
PP_EXPECT(h, commands_after_readback[14].kind == RecordedRenderCommandKind::read_texture);
|
||||
PP_EXPECT(h, commands_after_readback[14].texture_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_readback[14].readback_region.x == 4U);
|
||||
PP_EXPECT(h, commands_after_readback[14].readback_region.height == 3U);
|
||||
PP_EXPECT(h, commands_after_readback[14].readback_bytes == 96U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[14].kind) == std::string_view("read_texture"));
|
||||
|
||||
PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok());
|
||||
const auto commands_after_capture = device.commands();
|
||||
PP_EXPECT(h, commands_after_capture.size() == 15U);
|
||||
PP_EXPECT(h, commands_after_capture[14].kind == RecordedRenderCommandKind::capture_frame);
|
||||
PP_EXPECT(h, commands_after_capture[14].target_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_capture[14].target_desc.extent.height == 32U);
|
||||
PP_EXPECT(h, commands_after_capture[14].capture_bytes == 8192U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[14].kind) == std::string_view("capture_frame"));
|
||||
PP_EXPECT(h, commands_after_capture.size() == 16U);
|
||||
PP_EXPECT(h, commands_after_capture[15].kind == RecordedRenderCommandKind::capture_frame);
|
||||
PP_EXPECT(h, commands_after_capture[15].target_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_capture[15].target_desc.extent.height == 32U);
|
||||
PP_EXPECT(h, commands_after_capture[15].capture_bytes == 8192U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[15].kind) == std::string_view("capture_frame"));
|
||||
|
||||
PP_EXPECT(h, context.blit_render_target(
|
||||
target,
|
||||
@@ -1421,16 +1519,16 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
||||
BlitFilter::linear)
|
||||
.ok());
|
||||
const auto commands_after_blit = device.commands();
|
||||
PP_EXPECT(h, commands_after_blit.size() == 16U);
|
||||
PP_EXPECT(h, commands_after_blit[15].kind == RecordedRenderCommandKind::blit_render_target);
|
||||
PP_EXPECT(h, commands_after_blit[15].source_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_blit[15].destination_desc.extent.height == 32U);
|
||||
PP_EXPECT(h, commands_after_blit[15].source_region.width == 16U);
|
||||
PP_EXPECT(h, commands_after_blit[15].destination_region.x == 2U);
|
||||
PP_EXPECT(h, commands_after_blit[15].blit_filter == BlitFilter::linear);
|
||||
PP_EXPECT(h, commands_after_blit[15].blit_source_bytes == 512U);
|
||||
PP_EXPECT(h, commands_after_blit[15].blit_destination_bytes == 128U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_blit[15].kind) == std::string_view("blit_render_target"));
|
||||
PP_EXPECT(h, commands_after_blit.size() == 17U);
|
||||
PP_EXPECT(h, commands_after_blit[16].kind == RecordedRenderCommandKind::blit_render_target);
|
||||
PP_EXPECT(h, commands_after_blit[16].source_desc.extent.width == 64U);
|
||||
PP_EXPECT(h, commands_after_blit[16].destination_desc.extent.height == 32U);
|
||||
PP_EXPECT(h, commands_after_blit[16].source_region.width == 16U);
|
||||
PP_EXPECT(h, commands_after_blit[16].destination_region.x == 2U);
|
||||
PP_EXPECT(h, commands_after_blit[16].blit_filter == BlitFilter::linear);
|
||||
PP_EXPECT(h, commands_after_blit[16].blit_source_bytes == 512U);
|
||||
PP_EXPECT(h, commands_after_blit[16].blit_destination_bytes == 128U);
|
||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_blit[16].kind) == std::string_view("blit_render_target"));
|
||||
|
||||
device.clear();
|
||||
PP_EXPECT(h, device.commands().empty());
|
||||
@@ -1517,6 +1615,14 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !read_during_render_pass.ok());
|
||||
PP_EXPECT(h, read_during_render_pass.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto copy_during_render_pass = context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
PP_EXPECT(h, !copy_during_render_pass.ok());
|
||||
PP_EXPECT(h, copy_during_render_pass.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto capture_during_render_pass = context.capture_frame(target, full_readback_buffer);
|
||||
PP_EXPECT(h, !capture_during_render_pass.ok());
|
||||
PP_EXPECT(h, capture_during_render_pass.code == StatusCode::invalid_argument);
|
||||
@@ -1653,6 +1759,22 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !upload_outside_bounds.ok());
|
||||
PP_EXPECT(h, upload_outside_bounds.code == StatusCode::out_of_range);
|
||||
|
||||
const auto copy_mismatched_regions = context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 2, .height = 1 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
PP_EXPECT(h, !copy_mismatched_regions.ok());
|
||||
PP_EXPECT(h, copy_mismatched_regions.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto copy_outside_bounds = context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 31, .y = 15, .width = 2, .height = 1 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 2, .height = 1 });
|
||||
PP_EXPECT(h, !copy_outside_bounds.ok());
|
||||
PP_EXPECT(h, copy_outside_bounds.code == StatusCode::out_of_range);
|
||||
|
||||
const auto upload_with_wrong_size = context.upload_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
@@ -1723,6 +1845,7 @@ int main()
|
||||
harness.run("computes_readback_byte_sizes", computes_readback_byte_sizes);
|
||||
harness.run("computes_frame_capture_byte_sizes", computes_frame_capture_byte_sizes);
|
||||
harness.run("validates_blit_contract", validates_blit_contract);
|
||||
harness.run("validates_texture_copy_contract", validates_texture_copy_contract);
|
||||
harness.run("validates_blend_contract", validates_blend_contract);
|
||||
harness.run("validates_depth_contract", validates_depth_contract);
|
||||
harness.run("validates_sampler_contract", validates_sampler_contract);
|
||||
|
||||
Reference in New Issue
Block a user