Route RTT blit readback through renderer GL

This commit is contained in:
2026-06-03 06:31:41 +02:00
parent ae69f7437f
commit 3128a0d309
6 changed files with 487 additions and 73 deletions

View File

@@ -71,6 +71,19 @@ struct RecordedOpenGlReadPixelsCall {
void* pixels = nullptr;
};
struct RecordedOpenGlBlitFramebufferCall {
std::int32_t source_x0 = 0;
std::int32_t source_y0 = 0;
std::int32_t source_x1 = 0;
std::int32_t source_y1 = 0;
std::int32_t destination_x0 = 0;
std::int32_t destination_y0 = 0;
std::int32_t destination_x1 = 0;
std::int32_t destination_y1 = 0;
std::uint32_t mask = 0;
std::uint32_t filter = 0;
};
std::vector<RecordedOpenGlStateCall> recorded_state_calls;
std::vector<std::uint32_t> recorded_string_queries;
std::vector<pp::renderer::gl::OpenGlDefaultClear> recorded_clear_calls;
@@ -89,6 +102,7 @@ std::vector<std::uint32_t> recorded_deleted_framebuffers;
std::vector<RecordedOpenGlFramebufferAttachmentCall> recorded_framebuffer_attachment_calls;
std::vector<std::uint32_t> recorded_framebuffer_status_queries;
std::vector<RecordedOpenGlReadPixelsCall> recorded_read_pixels_calls;
std::vector<RecordedOpenGlBlitFramebufferCall> recorded_blit_framebuffer_calls;
std::uint32_t next_texture_id = 91U;
std::uint32_t next_framebuffer_id = 44U;
std::uint32_t configured_framebuffer_status = 0x8CD5U;
@@ -407,6 +421,32 @@ void record_read_pixels(
});
}
void record_blit_framebuffer(
std::int32_t source_x0,
std::int32_t source_y0,
std::int32_t source_x1,
std::int32_t source_y1,
std::int32_t destination_x0,
std::int32_t destination_y0,
std::int32_t destination_x1,
std::int32_t destination_y1,
std::uint32_t mask,
std::uint32_t filter) noexcept
{
recorded_blit_framebuffer_calls.push_back(RecordedOpenGlBlitFramebufferCall {
.source_x0 = source_x0,
.source_y0 = source_y0,
.source_x1 = source_x1,
.source_y1 = source_y1,
.destination_x0 = destination_x0,
.destination_y0 = destination_y0,
.destination_x1 = destination_x1,
.destination_y1 = destination_y1,
.mask = mask,
.filter = filter,
});
}
void detects_common_extension_capabilities(pp::tests::Harness& h)
{
constexpr std::array<std::string_view, 2> extensions {
@@ -1743,6 +1783,162 @@ void rejects_incomplete_texture_2d_readback_dispatch(pp::tests::Harness& h)
PP_EXPECT(h, result.status().code == pp::foundation::StatusCode::invalid_argument);
}
void blits_framebuffers_through_dispatch(pp::tests::Harness& h)
{
recorded_integer_queries.clear();
recorded_binding_calls.clear();
recorded_blit_framebuffer_calls.clear();
const auto status = pp::renderer::gl::blit_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferBlit {
.source_framebuffer = 13U,
.destination_framebuffer = 17U,
.source_rect = pp::renderer::gl::OpenGlFramebufferRect {
.x0 = 1,
.y0 = 2,
.x1 = 65,
.y1 = 34,
},
.destination_rect = pp::renderer::gl::OpenGlFramebufferRect {
.x0 = 3,
.y0 = 4,
.x1 = 131,
.y1 = 68,
},
.mask = 0x00004000U,
.filter = 0x2601U,
},
pp::renderer::gl::OpenGlFramebufferBlitDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
.blit_framebuffer = record_blit_framebuffer,
});
PP_EXPECT(h, status.ok());
PP_EXPECT(h, recorded_integer_queries.size() == 2U);
PP_EXPECT(h, recorded_integer_queries[0] == 0x8CA6U);
PP_EXPECT(h, recorded_integer_queries[1] == 0x8CAAU);
PP_EXPECT(h, recorded_binding_calls.size() == 4U);
PP_EXPECT(h, recorded_binding_calls[0].kind == RecordedOpenGlBindingCall::Kind::bind_framebuffer);
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8CA9U);
PP_EXPECT(h, recorded_binding_calls[0].second == 17U);
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8CA8U);
PP_EXPECT(h, recorded_binding_calls[1].second == 13U);
PP_EXPECT(h, recorded_binding_calls[2].first == 0x8CA9U);
PP_EXPECT(h, recorded_binding_calls[2].second == 7U);
PP_EXPECT(h, recorded_binding_calls[3].first == 0x8CA8U);
PP_EXPECT(h, recorded_binding_calls[3].second == 9U);
PP_EXPECT(h, recorded_blit_framebuffer_calls.size() == 1U);
PP_EXPECT(h, recorded_blit_framebuffer_calls[0].source_x0 == 1);
PP_EXPECT(h, recorded_blit_framebuffer_calls[0].source_y1 == 34);
PP_EXPECT(h, recorded_blit_framebuffer_calls[0].destination_x1 == 131);
PP_EXPECT(h, recorded_blit_framebuffer_calls[0].mask == 0x00004000U);
PP_EXPECT(h, recorded_blit_framebuffer_calls[0].filter == 0x2601U);
}
void rejects_invalid_framebuffer_blits(pp::tests::Harness& h)
{
const auto missing_dispatch = pp::renderer::gl::blit_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferBlit {
.source_rect = pp::renderer::gl::OpenGlFramebufferRect { .x1 = 1, .y1 = 1 },
.destination_rect = pp::renderer::gl::OpenGlFramebufferRect { .x1 = 1, .y1 = 1 },
.mask = 0x00004000U,
.filter = 0x2601U,
},
pp::renderer::gl::OpenGlFramebufferBlitDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
});
const auto empty_source = pp::renderer::gl::blit_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferBlit {
.source_rect = pp::renderer::gl::OpenGlFramebufferRect { .x1 = 0, .y1 = 1 },
.destination_rect = pp::renderer::gl::OpenGlFramebufferRect { .x1 = 1, .y1 = 1 },
.mask = 0x00004000U,
.filter = 0x2601U,
},
pp::renderer::gl::OpenGlFramebufferBlitDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
.blit_framebuffer = record_blit_framebuffer,
});
PP_EXPECT(h, !missing_dispatch.ok());
PP_EXPECT(h, missing_dispatch.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !empty_source.ok());
PP_EXPECT(h, empty_source.code == pp::foundation::StatusCode::invalid_argument);
}
void reads_back_framebuffer_through_dispatch(pp::tests::Harness& h)
{
recorded_integer_queries.clear();
recorded_binding_calls.clear();
recorded_read_pixels_calls.clear();
std::array<std::uint8_t, 16> pixels {};
const auto status = pp::renderer::gl::readback_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferReadback {
.framebuffer = 23U,
.x = 2,
.y = 3,
.width = 4,
.height = 5,
.format = pp::renderer::gl::rgba8_readback_format(),
.pixels = pixels.data(),
},
pp::renderer::gl::OpenGlFramebufferReadbackDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
.read_pixels = record_read_pixels,
});
PP_EXPECT(h, status.ok());
PP_EXPECT(h, recorded_integer_queries.size() == 1U);
PP_EXPECT(h, recorded_integer_queries[0] == 0x8CAAU);
PP_EXPECT(h, recorded_binding_calls.size() == 2U);
PP_EXPECT(h, recorded_binding_calls[0].first == 0x8CA8U);
PP_EXPECT(h, recorded_binding_calls[0].second == 23U);
PP_EXPECT(h, recorded_binding_calls[1].first == 0x8CA8U);
PP_EXPECT(h, recorded_binding_calls[1].second == 9U);
PP_EXPECT(h, recorded_read_pixels_calls.size() == 1U);
PP_EXPECT(h, recorded_read_pixels_calls[0].x == 2);
PP_EXPECT(h, recorded_read_pixels_calls[0].y == 3);
PP_EXPECT(h, recorded_read_pixels_calls[0].width == 4);
PP_EXPECT(h, recorded_read_pixels_calls[0].height == 5);
PP_EXPECT(h, recorded_read_pixels_calls[0].pixels == pixels.data());
}
void rejects_invalid_framebuffer_readbacks(pp::tests::Harness& h)
{
std::array<std::uint8_t, 4> pixels {};
const auto missing_dispatch = pp::renderer::gl::readback_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferReadback {
.width = 1,
.height = 1,
.format = pp::renderer::gl::rgba8_readback_format(),
.pixels = pixels.data(),
},
pp::renderer::gl::OpenGlFramebufferReadbackDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
});
const auto missing_pixels = pp::renderer::gl::readback_opengl_framebuffer(
pp::renderer::gl::OpenGlFramebufferReadback {
.width = 1,
.height = 1,
.format = pp::renderer::gl::rgba8_readback_format(),
},
pp::renderer::gl::OpenGlFramebufferReadbackDispatch {
.get_integer = record_get_integer,
.bind_framebuffer = record_bind_framebuffer,
.read_pixels = record_read_pixels,
});
PP_EXPECT(h, !missing_dispatch.ok());
PP_EXPECT(h, missing_dispatch.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !missing_pixels.ok());
PP_EXPECT(h, missing_pixels.code == pp::foundation::StatusCode::invalid_argument);
}
void maps_renderer_viewports_and_scissors(pp::tests::Harness& h)
{
const auto viewport = pp::renderer::gl::viewport_for_renderer_viewport(
@@ -2145,6 +2341,10 @@ int main()
harness.run("reads_back_texture_2d_through_framebuffer_dispatch", reads_back_texture_2d_through_framebuffer_dispatch);
harness.run("reports_incomplete_texture_2d_readback_framebuffer", reports_incomplete_texture_2d_readback_framebuffer);
harness.run("rejects_incomplete_texture_2d_readback_dispatch", rejects_incomplete_texture_2d_readback_dispatch);
harness.run("blits_framebuffers_through_dispatch", blits_framebuffers_through_dispatch);
harness.run("rejects_invalid_framebuffer_blits", rejects_invalid_framebuffer_blits);
harness.run("reads_back_framebuffer_through_dispatch", reads_back_framebuffer_through_dispatch);
harness.run("rejects_invalid_framebuffer_readbacks", rejects_invalid_framebuffer_readbacks);
harness.run("maps_renderer_viewports_and_scissors", maps_renderer_viewports_and_scissors);
harness.run("maps_renderer_blend_state_tokens", maps_renderer_blend_state_tokens);
harness.run("maps_renderer_color_write_masks", maps_renderer_color_write_masks);