Add renderer texture upload contract
This commit is contained in:
@@ -285,12 +285,13 @@ Known local toolchain state:
|
|||||||
source code reintroduces raw `GL_*`/`WGL_*` constants outside the allowed
|
source code reintroduces raw `GL_*`/`WGL_*` constants outside the allowed
|
||||||
legacy OpenGL implementation files.
|
legacy OpenGL implementation files.
|
||||||
- `pp_renderer_api` exposes a headless `RecordingRenderDevice` that validates
|
- `pp_renderer_api` exposes a headless `RecordingRenderDevice` that validates
|
||||||
command order, readback bounds, frame-capture sources, and destination buffer
|
command order, texture-upload byte counts, readback bounds, frame-capture
|
||||||
sizes, records render/readback/frame-capture commands, and records trace
|
sources, and destination buffer sizes, records render/upload/readback/
|
||||||
markers without a window or GL context.
|
frame-capture commands, and records trace markers without a window or GL
|
||||||
|
context.
|
||||||
- `pano_cli record-render` exposes the recording renderer through JSON
|
- `pano_cli record-render` exposes the recording renderer through JSON
|
||||||
automation, including readback and frame-capture command/byte totals, and is
|
automation, including upload/readback/frame-capture command and byte totals,
|
||||||
covered by `pano_cli_record_render_smoke` plus
|
and is covered by `pano_cli_record_render_smoke` plus
|
||||||
`pano_cli_record_render_rejects_oversized_target`.
|
`pano_cli_record_render_rejects_oversized_target`.
|
||||||
- `pano_cli simulate-document-history` exposes `pp_document::DocumentHistory`
|
- `pano_cli simulate-document-history` exposes `pp_document::DocumentHistory`
|
||||||
apply/undo/redo state through JSON automation and is covered by
|
apply/undo/redo state through JSON automation and is covered by
|
||||||
|
|||||||
@@ -416,10 +416,10 @@ adding new backends.
|
|||||||
Status: started. `pp_renderer_api` exists as a headless renderer-neutral target
|
Status: started. `pp_renderer_api` exists as a headless renderer-neutral target
|
||||||
with texture descriptor, byte-size, viewport, mesh, readback bounds, command
|
with texture descriptor, byte-size, viewport, mesh, readback bounds, command
|
||||||
context, render device, shader program descriptor, mesh, render target,
|
context, render device, shader program descriptor, mesh, render target,
|
||||||
readback byte-size helpers, readback command validation, frame-capture
|
readback byte-size helpers, texture-upload/readback command validation,
|
||||||
byte-size helpers, frame-capture command validation, trace interface
|
frame-capture byte-size helpers, frame-capture command validation, trace
|
||||||
validation, and the canonical PanoPainter shader catalog now consumed by the
|
interface validation, and the canonical PanoPainter shader catalog now consumed
|
||||||
legacy OpenGL app initialization path.
|
by the legacy OpenGL app initialization path.
|
||||||
`pp_renderer_gl` now exists as the first OpenGL backend library and owns pure
|
`pp_renderer_gl` now exists as the first OpenGL backend library and owns pure
|
||||||
OpenGL capability detection for framebuffer fetch, map-buffer alignment, and
|
OpenGL capability detection for framebuffer fetch, map-buffer alignment, and
|
||||||
float texture support. It also owns the OpenGL texture upload-type mapping used
|
float texture support. It also owns the OpenGL texture upload-type mapping used
|
||||||
@@ -719,8 +719,9 @@ Results:
|
|||||||
plus malformed payload rejection at the export boundary.
|
plus malformed payload rejection at the export boundary.
|
||||||
- `pp_renderer_api_tests` passed, including shader descriptor validation,
|
- `pp_renderer_api_tests` passed, including shader descriptor validation,
|
||||||
PanoPainter shader catalog validation, readback byte-size and command-order
|
PanoPainter shader catalog validation, readback byte-size and command-order
|
||||||
validation, frame-capture byte-size and command-order validation, recording
|
validation, texture-upload byte-count validation, frame-capture byte-size and
|
||||||
readback/frame-capture command capture, and invalid catalog rejection.
|
command-order validation, recording upload/readback/frame-capture command
|
||||||
|
capture, and invalid catalog rejection.
|
||||||
- `pp_paint_renderer_compositor_tests` passed.
|
- `pp_paint_renderer_compositor_tests` passed.
|
||||||
- `pp_ui_core_color_tests` passed.
|
- `pp_ui_core_color_tests` passed.
|
||||||
- `pp_ui_core_layout_value_tests` passed.
|
- `pp_ui_core_layout_value_tests` passed.
|
||||||
@@ -814,13 +815,15 @@ Results:
|
|||||||
reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL
|
reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL
|
||||||
implementation files.
|
implementation files.
|
||||||
- `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict
|
- `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict
|
||||||
command-order/readback/frame-capture validation; it records commands, trace
|
command-order/texture-upload/readback/frame-capture validation; it records
|
||||||
markers, texture readbacks, and frame captures, giving automation a
|
commands, trace markers, texture uploads/readbacks, and frame captures, giving
|
||||||
backend-neutral render path that does not require a window or GL context.
|
automation a backend-neutral render path that does not require a window or GL
|
||||||
|
context.
|
||||||
- `pano_cli record-render` exercises that headless recording renderer and emits
|
- `pano_cli record-render` exercises that headless recording renderer and emits
|
||||||
JSON command counts, target dimensions, backend name, trace/draw summary, and
|
JSON command counts, target dimensions, backend name, trace/draw summary, and
|
||||||
readback/frame-capture command/byte totals for agent automation, with an
|
texture-upload/readback/frame-capture command/byte totals for agent
|
||||||
expected-failure smoke for oversized render/readback targets.
|
automation, with an expected-failure smoke for oversized render/readback
|
||||||
|
targets.
|
||||||
- `pano_cli simulate-document-history` exercises pure document history
|
- `pano_cli simulate-document-history` exercises pure document history
|
||||||
apply/undo/redo behavior and emits JSON layer/frame/history state for agent
|
apply/undo/redo behavior and emits JSON layer/frame/history state for agent
|
||||||
automation.
|
automation.
|
||||||
|
|||||||
@@ -202,6 +202,34 @@ pp::foundation::Status RecordingCommandContext::read_texture(
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status RecordingCommandContext::upload_texture(
|
||||||
|
ITexture2D& texture,
|
||||||
|
ReadbackRegion region,
|
||||||
|
std::span<const std::byte> rgba_or_channel_bytes) noexcept
|
||||||
|
{
|
||||||
|
if (in_render_pass_) {
|
||||||
|
return pp::foundation::Status::invalid_argument("texture upload must be outside a render pass");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto desc = texture.desc();
|
||||||
|
const auto bytes = readback_byte_size(desc, region);
|
||||||
|
if (!bytes) {
|
||||||
|
return bytes.status();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rgba_or_channel_bytes.size() != bytes.value()) {
|
||||||
|
return pp::foundation::Status::invalid_argument("texture upload byte size does not match the region");
|
||||||
|
}
|
||||||
|
|
||||||
|
push_command(commands_, RecordedRenderCommand {
|
||||||
|
.kind = RecordedRenderCommandKind::upload_texture,
|
||||||
|
.texture_desc = desc,
|
||||||
|
.readback_region = region,
|
||||||
|
.upload_bytes = bytes.value(),
|
||||||
|
});
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Status RecordingCommandContext::capture_frame(
|
pp::foundation::Status RecordingCommandContext::capture_frame(
|
||||||
IRenderTarget& target,
|
IRenderTarget& target,
|
||||||
IReadbackBuffer& destination) noexcept
|
IReadbackBuffer& destination) noexcept
|
||||||
@@ -305,6 +333,8 @@ const char* recorded_render_command_kind_name(RecordedRenderCommandKind kind) no
|
|||||||
return "bind_mesh";
|
return "bind_mesh";
|
||||||
case RecordedRenderCommandKind::draw:
|
case RecordedRenderCommandKind::draw:
|
||||||
return "draw";
|
return "draw";
|
||||||
|
case RecordedRenderCommandKind::upload_texture:
|
||||||
|
return "upload_texture";
|
||||||
case RecordedRenderCommandKind::read_texture:
|
case RecordedRenderCommandKind::read_texture:
|
||||||
return "read_texture";
|
return "read_texture";
|
||||||
case RecordedRenderCommandKind::capture_frame:
|
case RecordedRenderCommandKind::capture_frame:
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ enum class RecordedRenderCommandKind : std::uint8_t {
|
|||||||
bind_shader,
|
bind_shader,
|
||||||
bind_mesh,
|
bind_mesh,
|
||||||
draw,
|
draw,
|
||||||
|
upload_texture,
|
||||||
read_texture,
|
read_texture,
|
||||||
capture_frame,
|
capture_frame,
|
||||||
end_render_pass,
|
end_render_pass,
|
||||||
@@ -27,6 +28,7 @@ struct RecordedRenderCommand {
|
|||||||
MeshDesc mesh_desc {};
|
MeshDesc mesh_desc {};
|
||||||
TextureDesc texture_desc {};
|
TextureDesc texture_desc {};
|
||||||
ReadbackRegion readback_region {};
|
ReadbackRegion readback_region {};
|
||||||
|
std::uint64_t upload_bytes = 0;
|
||||||
std::uint64_t readback_bytes = 0;
|
std::uint64_t readback_bytes = 0;
|
||||||
std::uint64_t capture_bytes = 0;
|
std::uint64_t capture_bytes = 0;
|
||||||
const char* component = "";
|
const char* component = "";
|
||||||
@@ -93,6 +95,10 @@ public:
|
|||||||
ITexture2D& texture,
|
ITexture2D& texture,
|
||||||
ReadbackRegion region,
|
ReadbackRegion region,
|
||||||
IReadbackBuffer& destination) noexcept override;
|
IReadbackBuffer& destination) noexcept override;
|
||||||
|
[[nodiscard]] pp::foundation::Status upload_texture(
|
||||||
|
ITexture2D& texture,
|
||||||
|
ReadbackRegion region,
|
||||||
|
std::span<const std::byte> rgba_or_channel_bytes) noexcept override;
|
||||||
[[nodiscard]] pp::foundation::Status capture_frame(
|
[[nodiscard]] pp::foundation::Status capture_frame(
|
||||||
IRenderTarget& target,
|
IRenderTarget& target,
|
||||||
IReadbackBuffer& destination) noexcept override;
|
IReadbackBuffer& destination) noexcept override;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace pp::renderer {
|
namespace pp::renderer {
|
||||||
|
|
||||||
@@ -126,6 +127,10 @@ public:
|
|||||||
ITexture2D& texture,
|
ITexture2D& texture,
|
||||||
ReadbackRegion region,
|
ReadbackRegion region,
|
||||||
IReadbackBuffer& destination) noexcept = 0;
|
IReadbackBuffer& destination) noexcept = 0;
|
||||||
|
[[nodiscard]] virtual pp::foundation::Status upload_texture(
|
||||||
|
ITexture2D& texture,
|
||||||
|
ReadbackRegion region,
|
||||||
|
std::span<const std::byte> rgba_or_channel_bytes) noexcept = 0;
|
||||||
[[nodiscard]] virtual pp::foundation::Status capture_frame(
|
[[nodiscard]] virtual pp::foundation::Status capture_frame(
|
||||||
IRenderTarget& target,
|
IRenderTarget& target,
|
||||||
IReadbackBuffer& destination) noexcept = 0;
|
IReadbackBuffer& destination) noexcept = 0;
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ if(TARGET pano_cli)
|
|||||||
COMMAND pano_cli record-render --width 32 --height 16)
|
COMMAND pano_cli record-render --width 32 --height 16)
|
||||||
set_tests_properties(pano_cli_record_render_smoke PROPERTIES
|
set_tests_properties(pano_cli_record_render_smoke PROPERTIES
|
||||||
LABELS "renderer;integration;desktop-fast"
|
LABELS "renderer;integration;desktop-fast"
|
||||||
PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"commands\":9.*\"drawCommands\":1.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048")
|
PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"commands\":10.*\"drawCommands\":1.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048")
|
||||||
|
|
||||||
add_test(NAME pano_cli_record_render_rejects_oversized_target
|
add_test(NAME pano_cli_record_render_rejects_oversized_target
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "test_harness.h"
|
#include "test_harness.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
using pp::foundation::StatusCode;
|
using pp::foundation::StatusCode;
|
||||||
@@ -168,6 +169,22 @@ public:
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] pp::foundation::Status upload_texture(
|
||||||
|
pp::renderer::ITexture2D& texture,
|
||||||
|
ReadbackRegion region,
|
||||||
|
std::span<const std::byte> rgba_or_channel_bytes) noexcept override
|
||||||
|
{
|
||||||
|
const auto bytes = readback_byte_size(texture.desc(), region);
|
||||||
|
if (!bytes) {
|
||||||
|
return bytes.status();
|
||||||
|
}
|
||||||
|
if (rgba_or_channel_bytes.size() != bytes.value()) {
|
||||||
|
return pp::foundation::Status::invalid_argument("texture upload byte size does not match the region");
|
||||||
|
}
|
||||||
|
last_upload_bytes = bytes.value();
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] pp::foundation::Status capture_frame(
|
[[nodiscard]] pp::foundation::Status capture_frame(
|
||||||
IRenderTarget& target,
|
IRenderTarget& target,
|
||||||
pp::renderer::IReadbackBuffer& destination) noexcept override
|
pp::renderer::IReadbackBuffer& destination) noexcept override
|
||||||
@@ -190,6 +207,7 @@ public:
|
|||||||
|
|
||||||
bool in_render_pass = false;
|
bool in_render_pass = false;
|
||||||
const char* shader_name = nullptr;
|
const char* shader_name = nullptr;
|
||||||
|
std::uint64_t last_upload_bytes = 0;
|
||||||
std::uint64_t last_readback_bytes = 0;
|
std::uint64_t last_readback_bytes = 0;
|
||||||
std::uint64_t last_capture_bytes = 0;
|
std::uint64_t last_capture_bytes = 0;
|
||||||
};
|
};
|
||||||
@@ -463,6 +481,7 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
|||||||
FakeRenderTarget target;
|
FakeRenderTarget target;
|
||||||
FakeTexture texture;
|
FakeTexture texture;
|
||||||
FakeReadbackBuffer readback_buffer(64U * 32U * 4U);
|
FakeReadbackBuffer readback_buffer(64U * 32U * 4U);
|
||||||
|
const std::array<std::byte, 80> upload_bytes {};
|
||||||
FakeShaderProgram shader;
|
FakeShaderProgram shader;
|
||||||
FakeMesh mesh;
|
FakeMesh mesh;
|
||||||
|
|
||||||
@@ -482,6 +501,11 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
|||||||
const auto draw_after_end = context.draw();
|
const auto draw_after_end = context.draw();
|
||||||
PP_EXPECT(h, !draw_after_end.ok());
|
PP_EXPECT(h, !draw_after_end.ok());
|
||||||
PP_EXPECT(h, draw_after_end.code == StatusCode::invalid_argument);
|
PP_EXPECT(h, draw_after_end.code == StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, context.upload_texture(
|
||||||
|
texture,
|
||||||
|
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
||||||
|
upload_bytes)
|
||||||
|
.ok());
|
||||||
PP_EXPECT(h, context.read_texture(
|
PP_EXPECT(h, context.read_texture(
|
||||||
texture,
|
texture,
|
||||||
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
ReadbackRegion { .x = 2, .y = 3, .width = 4, .height = 5 },
|
||||||
@@ -489,6 +513,7 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
|||||||
.ok());
|
.ok());
|
||||||
PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok());
|
PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok());
|
||||||
PP_EXPECT(h, device.context.shader_name == std::string_view("fake-shader"));
|
PP_EXPECT(h, device.context.shader_name == std::string_view("fake-shader"));
|
||||||
|
PP_EXPECT(h, device.context.last_upload_bytes == 80U);
|
||||||
PP_EXPECT(h, device.context.last_readback_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_capture_bytes == 8192U);
|
||||||
}
|
}
|
||||||
@@ -502,6 +527,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
.render_target = true,
|
.render_target = true,
|
||||||
});
|
});
|
||||||
RecordingReadbackBuffer readback_buffer(64U * 32U * 4U);
|
RecordingReadbackBuffer readback_buffer(64U * 32U * 4U);
|
||||||
|
const std::array<std::byte, 96> upload_bytes {};
|
||||||
RecordingRenderTarget target(TextureDesc {
|
RecordingRenderTarget target(TextureDesc {
|
||||||
.extent = Extent2D { .width = 64, .height = 32 },
|
.extent = Extent2D { .width = 64, .height = 32 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
@@ -539,28 +565,41 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, commands[6].kind == RecordedRenderCommandKind::end_render_pass);
|
PP_EXPECT(h, commands[6].kind == RecordedRenderCommandKind::end_render_pass);
|
||||||
PP_EXPECT(h, recorded_render_command_kind_name(commands[5].kind) == std::string_view("draw"));
|
PP_EXPECT(h, recorded_render_command_kind_name(commands[5].kind) == std::string_view("draw"));
|
||||||
|
|
||||||
|
PP_EXPECT(h, context.upload_texture(
|
||||||
|
texture,
|
||||||
|
ReadbackRegion { .x = 4, .y = 5, .width = 8, .height = 3 },
|
||||||
|
upload_bytes)
|
||||||
|
.ok());
|
||||||
|
const auto commands_after_upload = device.commands();
|
||||||
|
PP_EXPECT(h, commands_after_upload.size() == 8U);
|
||||||
|
PP_EXPECT(h, commands_after_upload[7].kind == RecordedRenderCommandKind::upload_texture);
|
||||||
|
PP_EXPECT(h, commands_after_upload[7].texture_desc.extent.width == 64U);
|
||||||
|
PP_EXPECT(h, commands_after_upload[7].readback_region.x == 4U);
|
||||||
|
PP_EXPECT(h, commands_after_upload[7].upload_bytes == 96U);
|
||||||
|
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_upload[7].kind) == std::string_view("upload_texture"));
|
||||||
|
|
||||||
PP_EXPECT(h, context.read_texture(
|
PP_EXPECT(h, context.read_texture(
|
||||||
texture,
|
texture,
|
||||||
ReadbackRegion { .x = 4, .y = 5, .width = 8, .height = 3 },
|
ReadbackRegion { .x = 4, .y = 5, .width = 8, .height = 3 },
|
||||||
readback_buffer)
|
readback_buffer)
|
||||||
.ok());
|
.ok());
|
||||||
const auto commands_after_readback = device.commands();
|
const auto commands_after_readback = device.commands();
|
||||||
PP_EXPECT(h, commands_after_readback.size() == 8U);
|
PP_EXPECT(h, commands_after_readback.size() == 9U);
|
||||||
PP_EXPECT(h, commands_after_readback[7].kind == RecordedRenderCommandKind::read_texture);
|
PP_EXPECT(h, commands_after_readback[8].kind == RecordedRenderCommandKind::read_texture);
|
||||||
PP_EXPECT(h, commands_after_readback[7].texture_desc.extent.width == 64U);
|
PP_EXPECT(h, commands_after_readback[8].texture_desc.extent.width == 64U);
|
||||||
PP_EXPECT(h, commands_after_readback[7].readback_region.x == 4U);
|
PP_EXPECT(h, commands_after_readback[8].readback_region.x == 4U);
|
||||||
PP_EXPECT(h, commands_after_readback[7].readback_region.height == 3U);
|
PP_EXPECT(h, commands_after_readback[8].readback_region.height == 3U);
|
||||||
PP_EXPECT(h, commands_after_readback[7].readback_bytes == 96U);
|
PP_EXPECT(h, commands_after_readback[8].readback_bytes == 96U);
|
||||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[7].kind) == std::string_view("read_texture"));
|
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_readback[8].kind) == std::string_view("read_texture"));
|
||||||
|
|
||||||
PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok());
|
PP_EXPECT(h, context.capture_frame(target, readback_buffer).ok());
|
||||||
const auto commands_after_capture = device.commands();
|
const auto commands_after_capture = device.commands();
|
||||||
PP_EXPECT(h, commands_after_capture.size() == 9U);
|
PP_EXPECT(h, commands_after_capture.size() == 10U);
|
||||||
PP_EXPECT(h, commands_after_capture[8].kind == RecordedRenderCommandKind::capture_frame);
|
PP_EXPECT(h, commands_after_capture[9].kind == RecordedRenderCommandKind::capture_frame);
|
||||||
PP_EXPECT(h, commands_after_capture[8].target_desc.extent.width == 64U);
|
PP_EXPECT(h, commands_after_capture[9].target_desc.extent.width == 64U);
|
||||||
PP_EXPECT(h, commands_after_capture[8].target_desc.extent.height == 32U);
|
PP_EXPECT(h, commands_after_capture[9].target_desc.extent.height == 32U);
|
||||||
PP_EXPECT(h, commands_after_capture[8].capture_bytes == 8192U);
|
PP_EXPECT(h, commands_after_capture[9].capture_bytes == 8192U);
|
||||||
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[8].kind) == std::string_view("capture_frame"));
|
PP_EXPECT(h, recorded_render_command_kind_name(commands_after_capture[9].kind) == std::string_view("capture_frame"));
|
||||||
|
|
||||||
device.clear();
|
device.clear();
|
||||||
PP_EXPECT(h, device.commands().empty());
|
PP_EXPECT(h, device.commands().empty());
|
||||||
@@ -586,6 +625,8 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
|||||||
});
|
});
|
||||||
RecordingReadbackBuffer small_readback_buffer(3U);
|
RecordingReadbackBuffer small_readback_buffer(3U);
|
||||||
RecordingReadbackBuffer full_readback_buffer(32U * 16U * 4U);
|
RecordingReadbackBuffer full_readback_buffer(32U * 16U * 4U);
|
||||||
|
const std::array<std::byte, 4> one_pixel_upload {};
|
||||||
|
const std::array<std::byte, 3> undersized_upload {};
|
||||||
RecordingShaderProgram shader("strict-shader");
|
RecordingShaderProgram shader("strict-shader");
|
||||||
RecordingMesh mesh(MeshDesc { .vertex_count = 3, .topology = PrimitiveTopology::triangles });
|
RecordingMesh mesh(MeshDesc { .vertex_count = 3, .topology = PrimitiveTopology::triangles });
|
||||||
RecordingMesh empty_mesh(MeshDesc {});
|
RecordingMesh empty_mesh(MeshDesc {});
|
||||||
@@ -601,6 +642,13 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
|||||||
PP_EXPECT(h, device.commands().empty());
|
PP_EXPECT(h, device.commands().empty());
|
||||||
|
|
||||||
PP_EXPECT(h, context.begin_render_pass(target, ClearColor {}).ok());
|
PP_EXPECT(h, context.begin_render_pass(target, ClearColor {}).ok());
|
||||||
|
const auto upload_during_render_pass = context.upload_texture(
|
||||||
|
texture,
|
||||||
|
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||||
|
one_pixel_upload);
|
||||||
|
PP_EXPECT(h, !upload_during_render_pass.ok());
|
||||||
|
PP_EXPECT(h, upload_during_render_pass.code == StatusCode::invalid_argument);
|
||||||
|
|
||||||
const auto read_during_render_pass = context.read_texture(
|
const auto read_during_render_pass = context.read_texture(
|
||||||
texture,
|
texture,
|
||||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||||
@@ -644,6 +692,20 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
|||||||
PP_EXPECT(h, !read_outside_bounds.ok());
|
PP_EXPECT(h, !read_outside_bounds.ok());
|
||||||
PP_EXPECT(h, read_outside_bounds.code == StatusCode::out_of_range);
|
PP_EXPECT(h, read_outside_bounds.code == StatusCode::out_of_range);
|
||||||
|
|
||||||
|
const auto upload_outside_bounds = context.upload_texture(
|
||||||
|
texture,
|
||||||
|
ReadbackRegion { .x = 31, .y = 15, .width = 2, .height = 1 },
|
||||||
|
one_pixel_upload);
|
||||||
|
PP_EXPECT(h, !upload_outside_bounds.ok());
|
||||||
|
PP_EXPECT(h, upload_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 },
|
||||||
|
undersized_upload);
|
||||||
|
PP_EXPECT(h, !upload_with_wrong_size.ok());
|
||||||
|
PP_EXPECT(h, upload_with_wrong_size.code == StatusCode::invalid_argument);
|
||||||
|
|
||||||
const auto read_into_small_buffer = context.read_texture(
|
const auto read_into_small_buffer = context.read_texture(
|
||||||
texture,
|
texture,
|
||||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||||
|
|||||||
@@ -2223,6 +2223,12 @@ int record_render(int argc, char** argv)
|
|||||||
});
|
});
|
||||||
pp::renderer::RecordingReadbackBuffer readback_buffer(
|
pp::renderer::RecordingReadbackBuffer readback_buffer(
|
||||||
static_cast<std::uint64_t>(args.width) * args.height * 4U);
|
static_cast<std::uint64_t>(args.width) * args.height * 4U);
|
||||||
|
const std::array<std::byte, 4> upload_pixel {
|
||||||
|
std::byte { 0xff },
|
||||||
|
std::byte { 0x00 },
|
||||||
|
std::byte { 0xff },
|
||||||
|
std::byte { 0xff },
|
||||||
|
};
|
||||||
pp::renderer::RecordingShaderProgram shader("pano-cli-record-render");
|
pp::renderer::RecordingShaderProgram shader("pano-cli-record-render");
|
||||||
pp::renderer::RecordingMesh mesh(pp::renderer::MeshDesc {
|
pp::renderer::RecordingMesh mesh(pp::renderer::MeshDesc {
|
||||||
.vertex_count = 3,
|
.vertex_count = 3,
|
||||||
@@ -2232,6 +2238,20 @@ int record_render(int argc, char** argv)
|
|||||||
|
|
||||||
device.trace()->marker("renderer", "pano_cli_record_render");
|
device.trace()->marker("renderer", "pano_cli_record_render");
|
||||||
auto& context = device.immediate_context();
|
auto& context = device.immediate_context();
|
||||||
|
const auto upload_status = context.upload_texture(
|
||||||
|
texture,
|
||||||
|
pp::renderer::ReadbackRegion {
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = 1,
|
||||||
|
.height = 1,
|
||||||
|
},
|
||||||
|
upload_pixel);
|
||||||
|
if (!upload_status.ok()) {
|
||||||
|
print_error("record-render", upload_status.message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
const auto begin_status = context.begin_render_pass(
|
const auto begin_status = context.begin_render_pass(
|
||||||
target,
|
target,
|
||||||
pp::renderer::ClearColor { .r = 0.0F, .g = 0.0F, .b = 0.0F, .a = 1.0F });
|
pp::renderer::ClearColor { .r = 0.0F, .g = 0.0F, .b = 0.0F, .a = 1.0F });
|
||||||
@@ -2286,15 +2306,20 @@ int record_render(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::size_t draw_commands = 0;
|
std::size_t draw_commands = 0;
|
||||||
|
std::size_t upload_commands = 0;
|
||||||
std::size_t readback_commands = 0;
|
std::size_t readback_commands = 0;
|
||||||
std::size_t capture_commands = 0;
|
std::size_t capture_commands = 0;
|
||||||
std::size_t trace_markers = 0;
|
std::size_t trace_markers = 0;
|
||||||
|
std::uint64_t upload_bytes = 0;
|
||||||
std::uint64_t readback_bytes = 0;
|
std::uint64_t readback_bytes = 0;
|
||||||
std::uint64_t capture_bytes = 0;
|
std::uint64_t capture_bytes = 0;
|
||||||
const auto commands = device.commands();
|
const auto commands = device.commands();
|
||||||
for (const auto& command : commands) {
|
for (const auto& command : commands) {
|
||||||
if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) {
|
if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) {
|
||||||
++draw_commands;
|
++draw_commands;
|
||||||
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::upload_texture) {
|
||||||
|
++upload_commands;
|
||||||
|
upload_bytes += command.upload_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::read_texture) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::read_texture) {
|
||||||
++readback_commands;
|
++readback_commands;
|
||||||
readback_bytes += command.readback_bytes;
|
readback_bytes += command.readback_bytes;
|
||||||
@@ -2313,6 +2338,8 @@ int record_render(int argc, char** argv)
|
|||||||
<< ",\"format\":\"rgba8\"}"
|
<< ",\"format\":\"rgba8\"}"
|
||||||
<< ",\"commands\":" << commands.size()
|
<< ",\"commands\":" << commands.size()
|
||||||
<< ",\"drawCommands\":" << draw_commands
|
<< ",\"drawCommands\":" << draw_commands
|
||||||
|
<< ",\"uploadCommands\":" << upload_commands
|
||||||
|
<< ",\"uploadBytes\":" << upload_bytes
|
||||||
<< ",\"readbackCommands\":" << readback_commands
|
<< ",\"readbackCommands\":" << readback_commands
|
||||||
<< ",\"readbackBytes\":" << readback_bytes
|
<< ",\"readbackBytes\":" << readback_bytes
|
||||||
<< ",\"captureCommands\":" << capture_commands
|
<< ",\"captureCommands\":" << capture_commands
|
||||||
|
|||||||
Reference in New Issue
Block a user