Add renderer resource label contract
This commit is contained in:
@@ -288,7 +288,7 @@ Known local toolchain state:
|
|||||||
backend-owned resource creation, explicit texture usage flags, command order,
|
backend-owned resource creation, explicit texture usage flags, command order,
|
||||||
render-pass color/depth/stencil clear intent, scissor state, depth state,
|
render-pass color/depth/stencil clear intent, scissor state, depth state,
|
||||||
blend state, texture-slot binding, sampler-state binding, texture-upload byte
|
blend state, texture-slot binding, sampler-state binding, texture-upload byte
|
||||||
counts, texture mip-level counts, mipmap-generation commands,
|
counts, texture mip-level counts, resource debug labels, mipmap-generation commands,
|
||||||
shader-uniform writes, explicit draw descriptor ranges, texture-copy regions,
|
shader-uniform writes, explicit draw descriptor ranges, texture-copy regions,
|
||||||
readback bounds, frame-capture sources, destination buffer sizes, and
|
readback bounds, frame-capture sources, destination buffer sizes, and
|
||||||
render-target blit regions, records
|
render-target blit regions, records
|
||||||
@@ -300,8 +300,8 @@ Known local toolchain state:
|
|||||||
automation, including render-pass/depth-clear counts, scissor/depth/blend/
|
automation, including render-pass/depth-clear counts, scissor/depth/blend/
|
||||||
shader-uniform/texture-bind/sampler-bind/upload/texture-copy/readback/
|
shader-uniform/texture-bind/sampler-bind/upload/texture-copy/readback/
|
||||||
frame-capture/blit command and byte totals, trace marker/scope counts,
|
frame-capture/blit command and byte totals, trace marker/scope counts,
|
||||||
backend resource creation counts, plus draw descriptor vertex/index totals,
|
labeled descriptor counts, backend resource creation counts, plus draw
|
||||||
and is covered by
|
descriptor vertex/index totals, and is covered by
|
||||||
`pano_cli_record_render_smoke` plus
|
`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`
|
||||||
|
|||||||
@@ -417,7 +417,8 @@ Status: started. `pp_renderer_api` exists as a headless renderer-neutral target
|
|||||||
with explicit texture usage flags, texture descriptor, byte-size, viewport,
|
with explicit texture usage flags, texture descriptor, byte-size, viewport,
|
||||||
mesh, readback bounds, command context, render device, shader program
|
mesh, readback bounds, command context, render device, shader program
|
||||||
descriptor, mesh, render target, readback byte-size helpers,
|
descriptor, mesh, render target, readback byte-size helpers,
|
||||||
texture mip-level validation, texture-upload/readback command validation,
|
texture mip-level validation, resource debug-label validation,
|
||||||
|
texture-upload/readback command validation,
|
||||||
mipmap-generation command validation, frame-capture byte-size helpers,
|
mipmap-generation command validation, frame-capture byte-size helpers,
|
||||||
frame-capture command validation, render-target blit validation, texture-slot
|
frame-capture command validation, render-target blit validation, texture-slot
|
||||||
binding validation, blend-state validation, scissor-state validation,
|
binding validation, blend-state validation, scissor-state validation,
|
||||||
@@ -723,10 +724,10 @@ 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, explicit texture usage validation,
|
PanoPainter shader catalog validation, explicit texture usage validation,
|
||||||
texture mip-level validation, readback byte-size and command-order
|
texture mip-level validation, resource debug-label validation, readback
|
||||||
validation, texture-upload byte-count validation, mipmap-generation command
|
byte-size and command-order validation, texture-upload byte-count validation,
|
||||||
validation, trace marker/scope validation, frame-capture byte-size and
|
mipmap-generation command validation, trace marker/scope validation,
|
||||||
command-order validation,
|
frame-capture byte-size and command-order validation,
|
||||||
render-target blit validation, texture-slot binding validation, blend-state
|
render-target blit validation, texture-slot binding validation, blend-state
|
||||||
validation, scissor-state validation, render-pass color/depth/stencil clear
|
validation, scissor-state validation, render-pass color/depth/stencil clear
|
||||||
validation, shader-uniform write validation, draw descriptor/range
|
validation, shader-uniform write validation, draw descriptor/range
|
||||||
@@ -834,8 +835,8 @@ Results:
|
|||||||
texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/
|
texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/
|
||||||
mipmap-generation/readback/frame-capture/blit validation plus explicit draw
|
mipmap-generation/readback/frame-capture/blit validation plus explicit draw
|
||||||
descriptor and texture-copy validation; it creates validated textures,
|
descriptor and texture-copy validation; it creates validated textures,
|
||||||
render targets, shaders, meshes, and readback buffers, then records commands,
|
render targets, shaders, meshes, and readback buffers with validated debug
|
||||||
trace markers/scopes, render-pass
|
labels, then records commands, trace markers/scopes, render-pass
|
||||||
color/depth/stencil clear intent, scissor state, depth state, blend state,
|
color/depth/stencil clear intent, scissor state, depth state, blend state,
|
||||||
shader uniform writes, texture/sampler binds, draw mesh inputs, explicit draw
|
shader uniform writes, texture/sampler binds, draw mesh inputs, explicit draw
|
||||||
ranges, texture uploads/mipmap generations/copies/readbacks, frame captures,
|
ranges, texture uploads/mipmap generations/copies/readbacks, frame captures,
|
||||||
@@ -843,7 +844,8 @@ Results:
|
|||||||
does not require a window or GL context.
|
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, resource creation counts, target dimensions, backend
|
JSON command counts, resource creation counts, target dimensions, backend
|
||||||
name, trace marker/scope and draw summary, render-pass/depth-clear counts, and draw
|
name, trace marker/scope and draw summary, labeled descriptor counts,
|
||||||
|
render-pass/depth-clear counts, and draw
|
||||||
descriptor vertex/index totals, scissor/depth/blend-state plus
|
descriptor vertex/index totals, scissor/depth/blend-state plus
|
||||||
shader-uniform/texture/sampler-bind/upload/texture-copy/readback/
|
shader-uniform/texture/sampler-bind/upload/texture-copy/readback/
|
||||||
frame-capture/blit command/byte totals for agent automation, with an
|
frame-capture/blit command/byte totals for agent automation, with an
|
||||||
|
|||||||
@@ -131,6 +131,19 @@ pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept
|
|||||||
return pp::foundation::Status::success();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status validate_resource_label(const char* label) noexcept
|
||||||
|
{
|
||||||
|
if (label == nullptr) {
|
||||||
|
return pp::foundation::Status::invalid_argument("resource label must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bounded_c_string_length(label, max_resource_label_bytes) > max_resource_label_bytes) {
|
||||||
|
return pp::foundation::Status::out_of_range("resource label exceeds the configured limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept
|
pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept
|
||||||
{
|
{
|
||||||
const auto extent_status = validate_extent(desc.extent);
|
const auto extent_status = validate_extent(desc.extent);
|
||||||
@@ -150,7 +163,12 @@ pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept
|
|||||||
return pp::foundation::Status::out_of_range("texture mip level count exceeds the texture extent");
|
return pp::foundation::Status::out_of_range("texture mip level count exceeds the texture extent");
|
||||||
}
|
}
|
||||||
|
|
||||||
return validate_texture_usage(desc.usage);
|
const auto usage_status = validate_texture_usage(desc.usage);
|
||||||
|
if (!usage_status.ok()) {
|
||||||
|
return usage_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return validate_resource_label(desc.debug_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pp::foundation::Result<std::uint64_t> texture_byte_size(TextureDesc desc) noexcept
|
pp::foundation::Result<std::uint64_t> texture_byte_size(TextureDesc desc) noexcept
|
||||||
@@ -417,6 +435,11 @@ pp::foundation::Status validate_sampler_desc(SamplerDesc desc) noexcept
|
|||||||
|
|
||||||
pp::foundation::Status validate_mesh_desc(MeshDesc desc) noexcept
|
pp::foundation::Status validate_mesh_desc(MeshDesc desc) noexcept
|
||||||
{
|
{
|
||||||
|
const auto label_status = validate_resource_label(desc.debug_name);
|
||||||
|
if (!label_status.ok()) {
|
||||||
|
return label_status;
|
||||||
|
}
|
||||||
|
|
||||||
if (desc.vertex_count == 0) {
|
if (desc.vertex_count == 0) {
|
||||||
return pp::foundation::Status::invalid_argument("mesh must contain at least one vertex");
|
return pp::foundation::Status::invalid_argument("mesh must contain at least one vertex");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ constexpr std::uint64_t max_texture_bytes = 1024ULL * 1024ULL * 1024ULL;
|
|||||||
constexpr std::size_t max_shader_source_bytes = 4ULL * 1024ULL * 1024ULL;
|
constexpr std::size_t max_shader_source_bytes = 4ULL * 1024ULL * 1024ULL;
|
||||||
constexpr std::size_t max_shader_uniform_bytes = 64ULL * 1024ULL;
|
constexpr std::size_t max_shader_uniform_bytes = 64ULL * 1024ULL;
|
||||||
constexpr std::size_t max_trace_label_bytes = 256;
|
constexpr std::size_t max_trace_label_bytes = 256;
|
||||||
|
constexpr std::size_t max_resource_label_bytes = 256;
|
||||||
|
|
||||||
enum class TextureFormat : std::uint8_t {
|
enum class TextureFormat : std::uint8_t {
|
||||||
rgba8,
|
rgba8,
|
||||||
@@ -66,6 +67,7 @@ struct TextureDesc {
|
|||||||
| TextureUsage::readback_source
|
| TextureUsage::readback_source
|
||||||
| TextureUsage::copy_source
|
| TextureUsage::copy_source
|
||||||
| TextureUsage::copy_destination;
|
| TextureUsage::copy_destination;
|
||||||
|
const char* debug_name = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReadbackRegion {
|
struct ReadbackRegion {
|
||||||
@@ -190,6 +192,7 @@ struct MeshDesc {
|
|||||||
std::uint32_t vertex_count = 0;
|
std::uint32_t vertex_count = 0;
|
||||||
std::uint32_t index_count = 0;
|
std::uint32_t index_count = 0;
|
||||||
PrimitiveTopology topology = PrimitiveTopology::triangles;
|
PrimitiveTopology topology = PrimitiveTopology::triangles;
|
||||||
|
const char* debug_name = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DrawDesc {
|
struct DrawDesc {
|
||||||
@@ -322,6 +325,7 @@ public:
|
|||||||
[[nodiscard]] bool has_texture_usage(TextureUsage usage, TextureUsage required) noexcept;
|
[[nodiscard]] bool has_texture_usage(TextureUsage usage, TextureUsage required) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status validate_extent(Extent2D extent) noexcept;
|
[[nodiscard]] pp::foundation::Status validate_extent(Extent2D extent) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept;
|
[[nodiscard]] pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Status validate_resource_label(const char* label) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept;
|
[[nodiscard]] pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status validate_viewport(Viewport viewport, Extent2D target_extent) noexcept;
|
[[nodiscard]] pp::foundation::Status validate_viewport(Viewport viewport, Extent2D target_extent) noexcept;
|
||||||
[[nodiscard]] pp::foundation::Status validate_scissor(ScissorRect scissor, Extent2D target_extent) noexcept;
|
[[nodiscard]] pp::foundation::Status validate_scissor(ScissorRect scissor, Extent2D target_extent) noexcept;
|
||||||
|
|||||||
@@ -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.*\"createdResources\":6.*\"commands\":20.*\"renderPasses\":1.*\"depthClears\":1.*\"stencilClears\":0.*\"drawCommands\":1.*\"drawVertices\":3.*\"drawIndices\":3.*\"scissorCommands\":1.*\"blendCommands\":1.*\"depthCommands\":1.*\"uniformCommands\":1.*\"uniformBytes\":64.*\"bindTextureCommands\":1.*\"bindSamplerCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"copyCommands\":1.*\"copySourceBytes\":2048.*\"copyDestinationBytes\":2048.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048.*\"traceMarkers\":1.*\"traceBeginScopes\":1.*\"traceEndScopes\":1")
|
PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"width\":32.*\"height\":16.*\"createdResources\":6.*\"labeledCommandDescriptors\":10.*\"commands\":20.*\"renderPasses\":1.*\"depthClears\":1.*\"stencilClears\":0.*\"drawCommands\":1.*\"drawVertices\":3.*\"drawIndices\":3.*\"scissorCommands\":1.*\"blendCommands\":1.*\"depthCommands\":1.*\"uniformCommands\":1.*\"uniformBytes\":64.*\"bindTextureCommands\":1.*\"bindSamplerCommands\":1.*\"boundTextureBytes\":2048.*\"uploadCommands\":1.*\"uploadBytes\":4.*\"copyCommands\":1.*\"copySourceBytes\":2048.*\"copyDestinationBytes\":2048.*\"readbackCommands\":1.*\"readbackBytes\":2048.*\"captureCommands\":1.*\"captureBytes\":2048.*\"blitCommands\":1.*\"blitSourceBytes\":2048.*\"blitDestinationBytes\":2048.*\"traceMarkers\":1.*\"traceBeginScopes\":1.*\"traceEndScopes\":1")
|
||||||
|
|
||||||
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}"
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ using pp::renderer::Viewport;
|
|||||||
using pp::renderer::max_shader_source_bytes;
|
using pp::renderer::max_shader_source_bytes;
|
||||||
using pp::renderer::max_shader_uniform_bytes;
|
using pp::renderer::max_shader_uniform_bytes;
|
||||||
using pp::renderer::max_mip_levels_for_extent;
|
using pp::renderer::max_mip_levels_for_extent;
|
||||||
|
using pp::renderer::max_resource_label_bytes;
|
||||||
using pp::renderer::max_texture_dimension;
|
using pp::renderer::max_texture_dimension;
|
||||||
using pp::renderer::max_texture_slots;
|
using pp::renderer::max_texture_slots;
|
||||||
using pp::renderer::max_trace_label_bytes;
|
using pp::renderer::max_trace_label_bytes;
|
||||||
@@ -82,6 +83,7 @@ using pp::renderer::validate_mesh_desc;
|
|||||||
using pp::renderer::validate_mipmap_generation_desc;
|
using pp::renderer::validate_mipmap_generation_desc;
|
||||||
using pp::renderer::validate_readback_region;
|
using pp::renderer::validate_readback_region;
|
||||||
using pp::renderer::validate_render_pass_desc;
|
using pp::renderer::validate_render_pass_desc;
|
||||||
|
using pp::renderer::validate_resource_label;
|
||||||
using pp::renderer::validate_sampler_address_mode;
|
using pp::renderer::validate_sampler_address_mode;
|
||||||
using pp::renderer::validate_sampler_desc;
|
using pp::renderer::validate_sampler_desc;
|
||||||
using pp::renderer::validate_sampler_filter;
|
using pp::renderer::validate_sampler_filter;
|
||||||
@@ -744,6 +746,50 @@ void validates_texture_usage_contract(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, unknown_format.code == StatusCode::invalid_argument);
|
PP_EXPECT(h, unknown_format.code == StatusCode::invalid_argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void validates_resource_labels(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::array<char, max_resource_label_bytes + 2U> oversized_label {};
|
||||||
|
oversized_label.fill('r');
|
||||||
|
oversized_label[max_resource_label_bytes + 1U] = '\0';
|
||||||
|
|
||||||
|
PP_EXPECT(h, validate_resource_label("").ok());
|
||||||
|
PP_EXPECT(h, validate_resource_label("stroke-target").ok());
|
||||||
|
PP_EXPECT(h, validate_texture_desc(TextureDesc {
|
||||||
|
.extent = Extent2D { .width = 4, .height = 4 },
|
||||||
|
.format = TextureFormat::rgba8,
|
||||||
|
.debug_name = "paint-texture",
|
||||||
|
})
|
||||||
|
.ok());
|
||||||
|
PP_EXPECT(h, validate_mesh_desc(MeshDesc {
|
||||||
|
.vertex_count = 3,
|
||||||
|
.topology = PrimitiveTopology::triangles,
|
||||||
|
.debug_name = "brush-quad",
|
||||||
|
})
|
||||||
|
.ok());
|
||||||
|
|
||||||
|
const auto null_label = validate_resource_label(nullptr);
|
||||||
|
const auto oversized = validate_resource_label(oversized_label.data());
|
||||||
|
const auto null_texture_label = validate_texture_desc(TextureDesc {
|
||||||
|
.extent = Extent2D { .width = 4, .height = 4 },
|
||||||
|
.format = TextureFormat::rgba8,
|
||||||
|
.debug_name = nullptr,
|
||||||
|
});
|
||||||
|
const auto oversized_mesh_label = validate_mesh_desc(MeshDesc {
|
||||||
|
.vertex_count = 3,
|
||||||
|
.topology = PrimitiveTopology::triangles,
|
||||||
|
.debug_name = oversized_label.data(),
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !null_label.ok());
|
||||||
|
PP_EXPECT(h, null_label.code == StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !oversized.ok());
|
||||||
|
PP_EXPECT(h, oversized.code == StatusCode::out_of_range);
|
||||||
|
PP_EXPECT(h, !null_texture_label.ok());
|
||||||
|
PP_EXPECT(h, null_texture_label.code == StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !oversized_mesh_label.ok());
|
||||||
|
PP_EXPECT(h, oversized_mesh_label.code == StatusCode::out_of_range);
|
||||||
|
}
|
||||||
|
|
||||||
void validates_mipmap_generation_contract(pp::tests::Harness& h)
|
void validates_mipmap_generation_contract(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
const TextureDesc mipmapped_desc {
|
const TextureDesc mipmapped_desc {
|
||||||
@@ -1469,11 +1515,13 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
|||||||
.extent = Extent2D { .width = 8, .height = 4 },
|
.extent = Extent2D { .width = 8, .height = 4 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||||
|
.debug_name = "factory-texture",
|
||||||
});
|
});
|
||||||
const auto target = device.create_render_target(TextureDesc {
|
const auto target = device.create_render_target(TextureDesc {
|
||||||
.extent = Extent2D { .width = 8, .height = 4 },
|
.extent = Extent2D { .width = 8, .height = 4 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||||
|
.debug_name = "factory-target",
|
||||||
});
|
});
|
||||||
const auto shader = device.create_shader_program(ShaderProgramDesc {
|
const auto shader = device.create_shader_program(ShaderProgramDesc {
|
||||||
.debug_name = "factory-shader",
|
.debug_name = "factory-shader",
|
||||||
@@ -1484,18 +1532,22 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
|||||||
.vertex_count = 6,
|
.vertex_count = 6,
|
||||||
.index_count = 6,
|
.index_count = 6,
|
||||||
.topology = PrimitiveTopology::triangles,
|
.topology = PrimitiveTopology::triangles,
|
||||||
|
.debug_name = "factory-mesh",
|
||||||
});
|
});
|
||||||
const auto readback = device.create_readback_buffer(8U * 4U * 4U);
|
const auto readback = device.create_readback_buffer(8U * 4U * 4U);
|
||||||
|
|
||||||
PP_EXPECT(h, texture.ok());
|
PP_EXPECT(h, texture.ok());
|
||||||
PP_EXPECT(h, texture.value()->desc().extent.width == 8U);
|
PP_EXPECT(h, texture.value()->desc().extent.width == 8U);
|
||||||
PP_EXPECT(h, !has_texture_usage(texture.value()->desc().usage, TextureUsage::render_target));
|
PP_EXPECT(h, !has_texture_usage(texture.value()->desc().usage, TextureUsage::render_target));
|
||||||
|
PP_EXPECT(h, texture.value()->desc().debug_name == std::string_view("factory-texture"));
|
||||||
PP_EXPECT(h, target.ok());
|
PP_EXPECT(h, target.ok());
|
||||||
PP_EXPECT(h, has_texture_usage(target.value()->color_desc().usage, TextureUsage::render_target));
|
PP_EXPECT(h, has_texture_usage(target.value()->color_desc().usage, TextureUsage::render_target));
|
||||||
|
PP_EXPECT(h, target.value()->color_desc().debug_name == std::string_view("factory-target"));
|
||||||
PP_EXPECT(h, shader.ok());
|
PP_EXPECT(h, shader.ok());
|
||||||
PP_EXPECT(h, shader.value()->debug_name() == std::string_view("factory-shader"));
|
PP_EXPECT(h, shader.value()->debug_name() == std::string_view("factory-shader"));
|
||||||
PP_EXPECT(h, mesh.ok());
|
PP_EXPECT(h, mesh.ok());
|
||||||
PP_EXPECT(h, mesh.value()->desc().index_count == 6U);
|
PP_EXPECT(h, mesh.value()->desc().index_count == 6U);
|
||||||
|
PP_EXPECT(h, mesh.value()->desc().debug_name == std::string_view("factory-mesh"));
|
||||||
PP_EXPECT(h, readback.ok());
|
PP_EXPECT(h, readback.ok());
|
||||||
PP_EXPECT(h, readback.value()->size_bytes() == 128U);
|
PP_EXPECT(h, readback.value()->size_bytes() == 128U);
|
||||||
|
|
||||||
@@ -1620,6 +1672,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
.extent = Extent2D { .width = 64, .height = 32 },
|
.extent = Extent2D { .width = 64, .height = 32 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||||
|
.debug_name = "recorded-texture",
|
||||||
});
|
});
|
||||||
RecordingReadbackBuffer readback_buffer(64U * 32U * 4U);
|
RecordingReadbackBuffer readback_buffer(64U * 32U * 4U);
|
||||||
const std::array<std::byte, 96> upload_bytes {};
|
const std::array<std::byte, 96> upload_bytes {};
|
||||||
@@ -1627,14 +1680,21 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
.extent = Extent2D { .width = 64, .height = 32 },
|
.extent = Extent2D { .width = 64, .height = 32 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||||
|
.debug_name = "recorded-target",
|
||||||
});
|
});
|
||||||
RecordingRenderTarget blit_target(TextureDesc {
|
RecordingRenderTarget blit_target(TextureDesc {
|
||||||
.extent = Extent2D { .width = 64, .height = 32 },
|
.extent = Extent2D { .width = 64, .height = 32 },
|
||||||
.format = TextureFormat::rgba8,
|
.format = TextureFormat::rgba8,
|
||||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||||
|
.debug_name = "recorded-blit-target",
|
||||||
});
|
});
|
||||||
RecordingShaderProgram shader("recorded-shader");
|
RecordingShaderProgram shader("recorded-shader");
|
||||||
RecordingMesh mesh(MeshDesc { .vertex_count = 3, .index_count = 3, .topology = PrimitiveTopology::triangles });
|
RecordingMesh mesh(MeshDesc {
|
||||||
|
.vertex_count = 3,
|
||||||
|
.index_count = 3,
|
||||||
|
.topology = PrimitiveTopology::triangles,
|
||||||
|
.debug_name = "recorded-mesh",
|
||||||
|
});
|
||||||
|
|
||||||
PP_EXPECT(h, device.backend_name() == std::string_view("recording"));
|
PP_EXPECT(h, device.backend_name() == std::string_view("recording"));
|
||||||
PP_EXPECT(h, device.trace()->begin_scope("renderer", "recorded-frame").ok());
|
PP_EXPECT(h, device.trace()->begin_scope("renderer", "recorded-frame").ok());
|
||||||
@@ -1693,6 +1753,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, recorded_render_command_kind_name(commands[2].kind) == std::string_view("trace_end_scope"));
|
PP_EXPECT(h, recorded_render_command_kind_name(commands[2].kind) == std::string_view("trace_end_scope"));
|
||||||
PP_EXPECT(h, commands[3].kind == RecordedRenderCommandKind::begin_render_pass);
|
PP_EXPECT(h, commands[3].kind == RecordedRenderCommandKind::begin_render_pass);
|
||||||
PP_EXPECT(h, commands[3].target_desc.extent.width == 64U);
|
PP_EXPECT(h, commands[3].target_desc.extent.width == 64U);
|
||||||
|
PP_EXPECT(h, commands[3].target_desc.debug_name == std::string_view("recorded-target"));
|
||||||
PP_EXPECT(h, commands[3].clear_color_enabled);
|
PP_EXPECT(h, commands[3].clear_color_enabled);
|
||||||
PP_EXPECT(h, commands[3].clear_color.a == 1.0F);
|
PP_EXPECT(h, commands[3].clear_color.a == 1.0F);
|
||||||
PP_EXPECT(h, commands[3].clear_depth_enabled);
|
PP_EXPECT(h, commands[3].clear_depth_enabled);
|
||||||
@@ -1720,6 +1781,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, commands[9].kind == RecordedRenderCommandKind::bind_texture);
|
PP_EXPECT(h, commands[9].kind == RecordedRenderCommandKind::bind_texture);
|
||||||
PP_EXPECT(h, commands[9].texture_slot == 1U);
|
PP_EXPECT(h, commands[9].texture_slot == 1U);
|
||||||
PP_EXPECT(h, commands[9].texture_desc.extent.height == 32U);
|
PP_EXPECT(h, commands[9].texture_desc.extent.height == 32U);
|
||||||
|
PP_EXPECT(h, commands[9].texture_desc.debug_name == std::string_view("recorded-texture"));
|
||||||
PP_EXPECT(h, recorded_render_command_kind_name(commands[9].kind) == std::string_view("bind_texture"));
|
PP_EXPECT(h, recorded_render_command_kind_name(commands[9].kind) == std::string_view("bind_texture"));
|
||||||
PP_EXPECT(h, commands[10].kind == RecordedRenderCommandKind::bind_sampler);
|
PP_EXPECT(h, commands[10].kind == RecordedRenderCommandKind::bind_sampler);
|
||||||
PP_EXPECT(h, commands[10].sampler_slot == 1U);
|
PP_EXPECT(h, commands[10].sampler_slot == 1U);
|
||||||
@@ -1729,6 +1791,7 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, commands[11].kind == RecordedRenderCommandKind::bind_mesh);
|
PP_EXPECT(h, commands[11].kind == RecordedRenderCommandKind::bind_mesh);
|
||||||
PP_EXPECT(h, commands[11].mesh_desc.vertex_count == 3U);
|
PP_EXPECT(h, commands[11].mesh_desc.vertex_count == 3U);
|
||||||
PP_EXPECT(h, commands[11].mesh_desc.index_count == 3U);
|
PP_EXPECT(h, commands[11].mesh_desc.index_count == 3U);
|
||||||
|
PP_EXPECT(h, commands[11].mesh_desc.debug_name == std::string_view("recorded-mesh"));
|
||||||
PP_EXPECT(h, commands[12].kind == RecordedRenderCommandKind::draw);
|
PP_EXPECT(h, commands[12].kind == RecordedRenderCommandKind::draw);
|
||||||
PP_EXPECT(h, commands[12].mesh_desc.vertex_count == 3U);
|
PP_EXPECT(h, commands[12].mesh_desc.vertex_count == 3U);
|
||||||
PP_EXPECT(h, commands[12].mesh_desc.index_count == 3U);
|
PP_EXPECT(h, commands[12].mesh_desc.index_count == 3U);
|
||||||
@@ -2225,6 +2288,7 @@ int main()
|
|||||||
pp::tests::Harness harness;
|
pp::tests::Harness harness;
|
||||||
harness.run("computes_texture_sizes", computes_texture_sizes);
|
harness.run("computes_texture_sizes", computes_texture_sizes);
|
||||||
harness.run("validates_texture_usage_contract", validates_texture_usage_contract);
|
harness.run("validates_texture_usage_contract", validates_texture_usage_contract);
|
||||||
|
harness.run("validates_resource_labels", validates_resource_labels);
|
||||||
harness.run("validates_mipmap_generation_contract", validates_mipmap_generation_contract);
|
harness.run("validates_mipmap_generation_contract", validates_mipmap_generation_contract);
|
||||||
harness.run("rejects_invalid_or_excessive_extents", rejects_invalid_or_excessive_extents);
|
harness.run("rejects_invalid_or_excessive_extents", rejects_invalid_or_excessive_extents);
|
||||||
harness.run("validates_readback_bounds", validates_readback_bounds);
|
harness.run("validates_readback_bounds", validates_readback_bounds);
|
||||||
|
|||||||
@@ -1643,6 +1643,7 @@ pp::foundation::Status parse_simulate_document_edits_args(
|
|||||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||||
.format = pp::renderer::TextureFormat::rgba8,
|
.format = pp::renderer::TextureFormat::rgba8,
|
||||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||||
|
.debug_name = "record-render-texture",
|
||||||
});
|
});
|
||||||
if (!render_target_size) {
|
if (!render_target_size) {
|
||||||
return render_target_size.status();
|
return render_target_size.status();
|
||||||
@@ -2215,11 +2216,13 @@ int record_render(int argc, char** argv)
|
|||||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||||
.format = pp::renderer::TextureFormat::rgba8,
|
.format = pp::renderer::TextureFormat::rgba8,
|
||||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||||
|
.debug_name = "record-render-target",
|
||||||
});
|
});
|
||||||
const auto target = device.create_render_target(pp::renderer::TextureDesc {
|
const auto target = device.create_render_target(pp::renderer::TextureDesc {
|
||||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||||
.format = pp::renderer::TextureFormat::rgba8,
|
.format = pp::renderer::TextureFormat::rgba8,
|
||||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||||
|
.debug_name = "record-render-blit-target",
|
||||||
});
|
});
|
||||||
const auto blit_target = device.create_render_target(pp::renderer::TextureDesc {
|
const auto blit_target = device.create_render_target(pp::renderer::TextureDesc {
|
||||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||||
@@ -2251,6 +2254,7 @@ int record_render(int argc, char** argv)
|
|||||||
.vertex_count = 3,
|
.vertex_count = 3,
|
||||||
.index_count = 3,
|
.index_count = 3,
|
||||||
.topology = pp::renderer::PrimitiveTopology::triangles,
|
.topology = pp::renderer::PrimitiveTopology::triangles,
|
||||||
|
.debug_name = "record-render-mesh",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!texture.ok()) {
|
if (!texture.ok()) {
|
||||||
@@ -2495,10 +2499,17 @@ int record_render(int argc, char** argv)
|
|||||||
std::uint64_t capture_bytes = 0;
|
std::uint64_t capture_bytes = 0;
|
||||||
std::uint64_t blit_source_bytes = 0;
|
std::uint64_t blit_source_bytes = 0;
|
||||||
std::uint64_t blit_destination_bytes = 0;
|
std::uint64_t blit_destination_bytes = 0;
|
||||||
|
std::size_t labeled_command_descriptors = 0;
|
||||||
|
const auto count_label = [&labeled_command_descriptors](const char* label) {
|
||||||
|
if (label != nullptr && label[0] != '\0') {
|
||||||
|
++labeled_command_descriptors;
|
||||||
|
}
|
||||||
|
};
|
||||||
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::begin_render_pass) {
|
if (command.kind == pp::renderer::RecordedRenderCommandKind::begin_render_pass) {
|
||||||
++render_passes;
|
++render_passes;
|
||||||
|
count_label(command.target_desc.debug_name);
|
||||||
if (command.clear_depth_enabled) {
|
if (command.clear_depth_enabled) {
|
||||||
++depth_clears;
|
++depth_clears;
|
||||||
}
|
}
|
||||||
@@ -2507,6 +2518,7 @@ int record_render(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::draw) {
|
||||||
++draw_commands;
|
++draw_commands;
|
||||||
|
count_label(command.mesh_desc.debug_name);
|
||||||
draw_vertices += command.draw_desc.vertex_count;
|
draw_vertices += command.draw_desc.vertex_count;
|
||||||
draw_indices += command.draw_desc.index_count;
|
draw_indices += command.draw_desc.index_count;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::set_scissor) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::set_scissor) {
|
||||||
@@ -2520,27 +2532,39 @@ int record_render(int argc, char** argv)
|
|||||||
uniform_bytes += command.uniform_bytes;
|
uniform_bytes += command.uniform_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_texture) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_texture) {
|
||||||
++bind_texture_commands;
|
++bind_texture_commands;
|
||||||
|
count_label(command.texture_desc.debug_name);
|
||||||
const auto bound_bytes = pp::renderer::texture_byte_size(command.texture_desc);
|
const auto bound_bytes = pp::renderer::texture_byte_size(command.texture_desc);
|
||||||
if (bound_bytes.ok()) {
|
if (bound_bytes.ok()) {
|
||||||
bound_texture_bytes += bound_bytes.value();
|
bound_texture_bytes += bound_bytes.value();
|
||||||
}
|
}
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_sampler) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_sampler) {
|
||||||
++bind_sampler_commands;
|
++bind_sampler_commands;
|
||||||
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::bind_mesh) {
|
||||||
|
count_label(command.mesh_desc.debug_name);
|
||||||
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::generate_mipmaps) {
|
||||||
|
count_label(command.texture_desc.debug_name);
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::upload_texture) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::upload_texture) {
|
||||||
++upload_commands;
|
++upload_commands;
|
||||||
|
count_label(command.texture_desc.debug_name);
|
||||||
upload_bytes += command.upload_bytes;
|
upload_bytes += command.upload_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::copy_texture) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::copy_texture) {
|
||||||
++copy_commands;
|
++copy_commands;
|
||||||
|
count_label(command.source_desc.debug_name);
|
||||||
|
count_label(command.destination_desc.debug_name);
|
||||||
copy_source_bytes += command.copy_source_bytes;
|
copy_source_bytes += command.copy_source_bytes;
|
||||||
copy_destination_bytes += command.copy_destination_bytes;
|
copy_destination_bytes += command.copy_destination_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::read_texture) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::read_texture) {
|
||||||
++readback_commands;
|
++readback_commands;
|
||||||
|
count_label(command.texture_desc.debug_name);
|
||||||
readback_bytes += command.readback_bytes;
|
readback_bytes += command.readback_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::capture_frame) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::capture_frame) {
|
||||||
++capture_commands;
|
++capture_commands;
|
||||||
|
count_label(command.target_desc.debug_name);
|
||||||
capture_bytes += command.capture_bytes;
|
capture_bytes += command.capture_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::blit_render_target) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::blit_render_target) {
|
||||||
++blit_commands;
|
++blit_commands;
|
||||||
|
count_label(command.source_desc.debug_name);
|
||||||
|
count_label(command.destination_desc.debug_name);
|
||||||
blit_source_bytes += command.blit_source_bytes;
|
blit_source_bytes += command.blit_source_bytes;
|
||||||
blit_destination_bytes += command.blit_destination_bytes;
|
blit_destination_bytes += command.blit_destination_bytes;
|
||||||
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::trace_marker) {
|
} else if (command.kind == pp::renderer::RecordedRenderCommandKind::trace_marker) {
|
||||||
@@ -2558,6 +2582,7 @@ int record_render(int argc, char** argv)
|
|||||||
<< ",\"height\":" << args.height
|
<< ",\"height\":" << args.height
|
||||||
<< ",\"format\":\"rgba8\"}"
|
<< ",\"format\":\"rgba8\"}"
|
||||||
<< ",\"createdResources\":" << created_resources
|
<< ",\"createdResources\":" << created_resources
|
||||||
|
<< ",\"labeledCommandDescriptors\":" << labeled_command_descriptors
|
||||||
<< ",\"commands\":" << commands.size()
|
<< ",\"commands\":" << commands.size()
|
||||||
<< ",\"renderPasses\":" << render_passes
|
<< ",\"renderPasses\":" << render_passes
|
||||||
<< ",\"depthClears\":" << depth_clears
|
<< ",\"depthClears\":" << depth_clears
|
||||||
|
|||||||
Reference in New Issue
Block a user