Route PBO readbacks through GL backend

This commit is contained in:
2026-06-04 21:29:49 +02:00
parent 45802dfc7c
commit fc20851462
7 changed files with 523 additions and 46 deletions

View File

@@ -166,6 +166,13 @@ struct RecordedOpenGlBufferDataCall {
std::uint32_t usage = 0;
};
struct RecordedOpenGlBufferMapCall {
std::uint32_t target = 0;
std::intptr_t offset = 0;
std::intptr_t byte_count = 0;
std::uint32_t access = 0;
};
struct RecordedOpenGlVertexAttribPointerCall {
std::uint32_t index = 0;
std::int32_t component_count = 0;
@@ -237,6 +244,8 @@ std::vector<std::uint32_t> recorded_generated_vertex_array_counts;
std::vector<std::uint32_t> recorded_deleted_vertex_arrays;
std::vector<RecordedOpenGlBufferBindCall> recorded_buffer_bind_calls;
std::vector<RecordedOpenGlBufferDataCall> recorded_buffer_data_calls;
std::vector<RecordedOpenGlBufferMapCall> recorded_buffer_map_calls;
std::vector<std::uint32_t> recorded_buffer_unmap_calls;
std::vector<std::uint32_t> recorded_vertex_array_bind_calls;
std::vector<std::uint32_t> recorded_enabled_vertex_attributes;
std::vector<RecordedOpenGlVertexAttribPointerCall> recorded_vertex_attrib_pointer_calls;
@@ -1002,6 +1011,41 @@ void record_buffer_data(
});
}
void* record_map_buffer_range(
std::uint32_t target,
std::intptr_t offset,
std::intptr_t byte_count,
std::uint32_t access) noexcept
{
recorded_buffer_map_calls.push_back(RecordedOpenGlBufferMapCall {
.target = target,
.offset = offset,
.byte_count = byte_count,
.access = access,
});
return reinterpret_cast<void*>(0x1234U);
}
void* record_failed_map_buffer_range(
std::uint32_t target,
std::intptr_t offset,
std::intptr_t byte_count,
std::uint32_t access) noexcept
{
recorded_buffer_map_calls.push_back(RecordedOpenGlBufferMapCall {
.target = target,
.offset = offset,
.byte_count = byte_count,
.access = access,
});
return nullptr;
}
void record_unmap_buffer(std::uint32_t target) noexcept
{
recorded_buffer_unmap_calls.push_back(target);
}
void record_gen_vertex_arrays(std::uint32_t count, std::uint32_t* ids) noexcept
{
recorded_generated_vertex_array_counts.push_back(count);
@@ -3779,6 +3823,170 @@ void rejects_invalid_mesh_dispatch(pp::tests::Harness& h)
PP_EXPECT(h, missing_delete_dispatch.code == pp::foundation::StatusCode::invalid_argument);
}
void creates_reads_maps_and_deletes_pixel_buffers_through_dispatch(pp::tests::Harness& h)
{
recorded_generated_buffer_counts.clear();
recorded_buffer_bind_calls.clear();
recorded_buffer_data_calls.clear();
recorded_read_pixels_calls.clear();
recorded_buffer_map_calls.clear();
recorded_buffer_unmap_calls.clear();
recorded_deleted_buffers.clear();
next_buffer_id = 801U;
const auto allocated = pp::renderer::gl::allocate_opengl_pixel_buffer(
pp::renderer::gl::OpenGlPixelBufferAllocationDispatch {
.gen_buffers = record_gen_buffers,
});
const auto readback = pp::renderer::gl::readback_opengl_framebuffer_to_pixel_buffer(
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferReadbackDispatch {
.gen_buffers = record_gen_buffers,
.bind_buffer = record_bind_buffer,
.buffer_data = record_buffer_data,
.read_pixels = record_read_pixels,
});
const auto mapped = pp::renderer::gl::map_opengl_pixel_buffer(
readback.ok() ? readback.value() : 0U,
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferMapDispatch {
.bind_buffer = record_bind_buffer,
.map_buffer_range = record_map_buffer_range,
});
const auto unmap_status = pp::renderer::gl::unmap_opengl_pixel_buffer(
readback.ok() ? readback.value() : 0U,
pp::renderer::gl::OpenGlPixelBufferUnmapDispatch {
.bind_buffer = record_bind_buffer,
.unmap_buffer = record_unmap_buffer,
});
const auto delete_status = pp::renderer::gl::delete_opengl_pixel_buffer(
readback.ok() ? readback.value() : 0U,
pp::renderer::gl::OpenGlPixelBufferDeleteDispatch {
.delete_buffers = record_delete_buffers,
});
PP_EXPECT(h, allocated.ok());
PP_EXPECT(h, allocated.value() == 801U);
PP_EXPECT(h, readback.ok());
PP_EXPECT(h, readback.value() == 802U);
PP_EXPECT(h, mapped.ok());
PP_EXPECT(h, mapped.value() == reinterpret_cast<void*>(0x1234U));
PP_EXPECT(h, unmap_status.ok());
PP_EXPECT(h, delete_status.ok());
PP_EXPECT(h, recorded_generated_buffer_counts.size() == 2U);
PP_EXPECT(h, recorded_generated_buffer_counts[0] == 1U);
PP_EXPECT(h, recorded_generated_buffer_counts[1] == 1U);
PP_EXPECT(h, recorded_buffer_bind_calls.size() == 6U);
PP_EXPECT(h, recorded_buffer_bind_calls[0].target == 0x88EBU);
PP_EXPECT(h, recorded_buffer_bind_calls[0].buffer == 802U);
PP_EXPECT(h, recorded_buffer_bind_calls[1].target == 0x88EBU);
PP_EXPECT(h, recorded_buffer_bind_calls[1].buffer == 0U);
PP_EXPECT(h, recorded_buffer_bind_calls[2].buffer == 802U);
PP_EXPECT(h, recorded_buffer_bind_calls[3].buffer == 0U);
PP_EXPECT(h, recorded_buffer_bind_calls[4].buffer == 802U);
PP_EXPECT(h, recorded_buffer_bind_calls[5].buffer == 0U);
PP_EXPECT(h, recorded_buffer_data_calls.size() == 1U);
PP_EXPECT(h, recorded_buffer_data_calls[0].target == 0x88EBU);
PP_EXPECT(h, recorded_buffer_data_calls[0].byte_count == 128);
PP_EXPECT(h, recorded_buffer_data_calls[0].data == nullptr);
PP_EXPECT(h, recorded_buffer_data_calls[0].usage == 0x88E1U);
PP_EXPECT(h, recorded_read_pixels_calls.size() == 1U);
PP_EXPECT(h, recorded_read_pixels_calls[0].width == 8);
PP_EXPECT(h, recorded_read_pixels_calls[0].height == 4);
PP_EXPECT(h, recorded_read_pixels_calls[0].pixel_format == 0x1908U);
PP_EXPECT(h, recorded_read_pixels_calls[0].component_type == 0x1401U);
PP_EXPECT(h, recorded_read_pixels_calls[0].pixels == nullptr);
PP_EXPECT(h, recorded_buffer_map_calls.size() == 1U);
PP_EXPECT(h, recorded_buffer_map_calls[0].target == 0x88EBU);
PP_EXPECT(h, recorded_buffer_map_calls[0].offset == 0);
PP_EXPECT(h, recorded_buffer_map_calls[0].byte_count == 128);
PP_EXPECT(h, recorded_buffer_map_calls[0].access == 0x0001U);
PP_EXPECT(h, recorded_buffer_unmap_calls.size() == 1U);
PP_EXPECT(h, recorded_buffer_unmap_calls[0] == 0x88EBU);
PP_EXPECT(h, recorded_deleted_buffers.size() == 1U);
PP_EXPECT(h, recorded_deleted_buffers[0] == 802U);
}
void rejects_invalid_pixel_buffer_dispatch(pp::tests::Harness& h)
{
const auto missing_allocate_dispatch = pp::renderer::gl::allocate_opengl_pixel_buffer(
pp::renderer::gl::OpenGlPixelBufferAllocationDispatch {});
const auto missing_readback_dispatch = pp::renderer::gl::readback_opengl_framebuffer_to_pixel_buffer(
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferReadbackDispatch {});
const auto invalid_readback_size = pp::renderer::gl::readback_opengl_framebuffer_to_pixel_buffer(
0,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferReadbackDispatch {
.gen_buffers = record_gen_buffers,
.bind_buffer = record_bind_buffer,
.buffer_data = record_buffer_data,
.read_pixels = record_read_pixels,
});
const auto missing_map_dispatch = pp::renderer::gl::map_opengl_pixel_buffer(
1U,
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferMapDispatch {});
const auto invalid_map_buffer = pp::renderer::gl::map_opengl_pixel_buffer(
0U,
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferMapDispatch {
.bind_buffer = record_bind_buffer,
.map_buffer_range = record_map_buffer_range,
});
const auto failed_map = pp::renderer::gl::map_opengl_pixel_buffer(
1U,
8,
4,
pp::renderer::gl::rgba8_readback_format(),
pp::renderer::gl::OpenGlPixelBufferMapDispatch {
.bind_buffer = record_bind_buffer,
.map_buffer_range = record_failed_map_buffer_range,
});
const auto missing_unmap_dispatch = pp::renderer::gl::unmap_opengl_pixel_buffer(
1U,
pp::renderer::gl::OpenGlPixelBufferUnmapDispatch {});
const auto invalid_unmap_buffer = pp::renderer::gl::unmap_opengl_pixel_buffer(
0U,
pp::renderer::gl::OpenGlPixelBufferUnmapDispatch {
.bind_buffer = record_bind_buffer,
.unmap_buffer = record_unmap_buffer,
});
const auto missing_delete_dispatch = pp::renderer::gl::delete_opengl_pixel_buffer(
1U,
pp::renderer::gl::OpenGlPixelBufferDeleteDispatch {});
PP_EXPECT(h, !missing_allocate_dispatch.ok());
PP_EXPECT(h, missing_allocate_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !missing_readback_dispatch.ok());
PP_EXPECT(h, missing_readback_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_readback_size.ok());
PP_EXPECT(h, invalid_readback_size.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !missing_map_dispatch.ok());
PP_EXPECT(h, missing_map_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_map_buffer.ok());
PP_EXPECT(h, invalid_map_buffer.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !failed_map.ok());
PP_EXPECT(h, failed_map.status().code == pp::foundation::StatusCode::out_of_range);
PP_EXPECT(h, !missing_unmap_dispatch.ok());
PP_EXPECT(h, missing_unmap_dispatch.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_unmap_buffer.ok());
PP_EXPECT(h, invalid_unmap_buffer.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !missing_delete_dispatch.ok());
PP_EXPECT(h, missing_delete_dispatch.code == pp::foundation::StatusCode::invalid_argument);
}
void updates_texture_2d_through_dispatch(pp::tests::Harness& h)
{
recorded_binding_calls.clear();
@@ -4759,6 +4967,8 @@ int main()
harness.run("creates_single_vertex_array_mesh_with_deferred_upload", creates_single_vertex_array_mesh_with_deferred_upload);
harness.run("updates_draws_and_deletes_mesh_through_dispatch", updates_draws_and_deletes_mesh_through_dispatch);
harness.run("rejects_invalid_mesh_dispatch", rejects_invalid_mesh_dispatch);
harness.run("creates_reads_maps_and_deletes_pixel_buffers_through_dispatch", creates_reads_maps_and_deletes_pixel_buffers_through_dispatch);
harness.run("rejects_invalid_pixel_buffer_dispatch", rejects_invalid_pixel_buffer_dispatch);
harness.run("updates_texture_2d_through_dispatch", updates_texture_2d_through_dispatch);
harness.run("copies_framebuffer_to_texture_2d_through_dispatch", copies_framebuffer_to_texture_2d_through_dispatch);
harness.run("skips_zero_sized_framebuffer_to_texture_copies", skips_zero_sized_framebuffer_to_texture_copies);