Validate shader resource label bounds

This commit is contained in:
2026-06-02 18:00:30 +02:00
parent 9a7f4bc0d2
commit 22dfde8e7c
4 changed files with 36 additions and 3 deletions

View File

@@ -301,7 +301,7 @@ Known local toolchain state:
explicit texture usage flags, command order,
render-pass color/depth/stencil clear intent, scissor state, depth state,
blend state, texture-slot binding, sampler-state binding, texture-upload byte
counts, texture mip-level counts, resource debug labels, mipmap-generation commands,
counts, texture mip-level counts, texture/mesh/shader resource debug labels, mipmap-generation commands,
texture-state transitions, shader-uniform writes, explicit draw descriptor ranges, texture-copy regions,
readback bounds, frame-capture sources, destination buffer sizes, and
render-target blit regions, records

View File

@@ -431,6 +431,7 @@ mipmap-generation command validation, texture-state transition validation, frame
frame-capture command validation, render-target blit validation, texture-slot
binding validation, blend-state validation, scissor-state validation,
depth-state validation, trace marker/scope validation, sampler-state validation,
texture/mesh/shader resource-label validation,
recording-device reuse/reset validation, and the canonical PanoPainter shader
catalog now consumed by the legacy OpenGL app initialization path.
`pp_renderer_gl` now exists as the first OpenGL backend library and owns pure

View File

@@ -503,8 +503,9 @@ pp::foundation::Status validate_texture_slot(std::uint32_t slot) noexcept
pp::foundation::Status validate_shader_program_desc(ShaderProgramDesc desc) noexcept
{
if (desc.debug_name == nullptr) {
return pp::foundation::Status::invalid_argument("shader debug name must not be null");
const auto label_status = validate_resource_label(desc.debug_name);
if (!label_status.ok()) {
return label_status;
}
const auto vertex_status = validate_shader_stage_source(

View File

@@ -801,6 +801,13 @@ void validates_resource_labels(pp::tests::Harness& h)
.debug_name = "brush-quad",
})
.ok());
static constexpr char shader_source[] = "void main() {}";
PP_EXPECT(h, validate_shader_program_desc(ShaderProgramDesc {
.debug_name = "brush-shader",
.vertex = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
.fragment = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
})
.ok());
const auto null_label = validate_resource_label(nullptr);
const auto oversized = validate_resource_label(oversized_label.data());
@@ -814,6 +821,16 @@ void validates_resource_labels(pp::tests::Harness& h)
.topology = PrimitiveTopology::triangles,
.debug_name = oversized_label.data(),
});
const auto null_shader_label = validate_shader_program_desc(ShaderProgramDesc {
.debug_name = nullptr,
.vertex = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
.fragment = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
});
const auto oversized_shader_label = validate_shader_program_desc(ShaderProgramDesc {
.debug_name = oversized_label.data(),
.vertex = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
.fragment = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
});
PP_EXPECT(h, !null_label.ok());
PP_EXPECT(h, null_label.code == StatusCode::invalid_argument);
@@ -823,6 +840,10 @@ void validates_resource_labels(pp::tests::Harness& h)
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);
PP_EXPECT(h, !null_shader_label.ok());
PP_EXPECT(h, null_shader_label.code == StatusCode::invalid_argument);
PP_EXPECT(h, !oversized_shader_label.ok());
PP_EXPECT(h, oversized_shader_label.code == StatusCode::out_of_range);
}
void validates_mipmap_generation_contract(pp::tests::Harness& h)
@@ -1686,6 +1707,9 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
void render_devices_create_validated_resources(pp::tests::Harness& h)
{
static constexpr char shader_source[] = "void main() {}";
std::array<char, max_resource_label_bytes + 2U> oversized_label {};
oversized_label.fill('s');
oversized_label[max_resource_label_bytes + 1U] = '\0';
RecordingRenderDevice device;
const auto texture = device.create_texture(TextureDesc {
@@ -1750,6 +1774,11 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
.vertex = ShaderStageSource {},
.fragment = ShaderStageSource {},
});
const auto oversized_shader_label = device.create_shader_program(ShaderProgramDesc {
.debug_name = oversized_label.data(),
.vertex = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
.fragment = ShaderStageSource { .source = shader_source, .source_size = sizeof(shader_source) - 1U },
});
const auto bad_mesh = device.create_mesh(MeshDesc {});
const auto bad_readback = device.create_readback_buffer(0);
@@ -1759,6 +1788,8 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
PP_EXPECT(h, bad_target.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !bad_shader.ok());
PP_EXPECT(h, bad_shader.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !oversized_shader_label.ok());
PP_EXPECT(h, oversized_shader_label.status().code == StatusCode::out_of_range);
PP_EXPECT(h, !bad_mesh.ok());
PP_EXPECT(h, bad_mesh.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !bad_readback.ok());