Validate renderer blit descriptors first

This commit is contained in:
2026-06-02 18:06:23 +02:00
parent 831e5deeae
commit 0fc73d51d2
4 changed files with 55 additions and 8 deletions

View File

@@ -303,7 +303,7 @@ Known local toolchain 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, texture/mesh/shader 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, texture-state transitions, shader-uniform writes, explicit draw descriptor ranges, texture-copy regions,
readback descriptor/bounds, frame-capture sources, destination buffer sizes, and readback/frame-capture/blit descriptor validation, readback bounds, destination buffer sizes, and
render-target blit regions, records render-target blit regions, records
render-pass-clear/scissor/depth/blend/shader-uniform/texture-bind/ render-pass-clear/scissor/depth/blend/shader-uniform/texture-bind/
sampler-bind/draw/upload/mipmap-generation/texture-transition/texture-copy/readback/ sampler-bind/draw/upload/mipmap-generation/texture-transition/texture-copy/readback/

View File

@@ -428,7 +428,7 @@ descriptor, mesh, render target, readback byte-size helpers,
texture mip-level validation, resource debug-label validation, texture mip-level validation, resource debug-label validation,
texture-upload/readback command validation, texture-upload/readback command validation,
mipmap-generation command validation, texture-state transition validation, frame-capture byte-size helpers, mipmap-generation command validation, texture-state transition validation, frame-capture byte-size helpers,
readback/copy descriptor validation, frame-capture command validation, render-target blit validation, texture-slot readback/copy/frame-capture/blit descriptor validation, 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,
depth-state validation, trace marker/scope validation, sampler-state validation, depth-state validation, trace marker/scope validation, sampler-state validation,
texture/mesh/shader resource-label validation, texture/mesh/shader resource-label validation,

View File

@@ -624,6 +624,11 @@ pp::foundation::Result<std::uint64_t> readback_byte_size(TextureDesc desc, Readb
pp::foundation::Result<std::uint64_t> frame_capture_byte_size(TextureDesc desc) noexcept pp::foundation::Result<std::uint64_t> frame_capture_byte_size(TextureDesc desc) noexcept
{ {
const auto desc_status = validate_texture_desc(desc);
if (!desc_status.ok()) {
return pp::foundation::Result<std::uint64_t>::failure(desc_status);
}
if (!has_texture_usage(desc.usage, TextureUsage::render_target)) { if (!has_texture_usage(desc.usage, TextureUsage::render_target)) {
return pp::foundation::Result<std::uint64_t>::failure( return pp::foundation::Result<std::uint64_t>::failure(
pp::foundation::Status::invalid_argument("frame capture source must be a render target")); pp::foundation::Status::invalid_argument("frame capture source must be a render target"));
@@ -778,6 +783,16 @@ pp::foundation::Status validate_blit_filter(BlitFilter filter) noexcept
pp::foundation::Status validate_blit_descs(TextureDesc source, TextureDesc destination) noexcept pp::foundation::Status validate_blit_descs(TextureDesc source, TextureDesc destination) noexcept
{ {
const auto source_status = validate_texture_desc(source);
if (!source_status.ok()) {
return source_status;
}
const auto destination_status = validate_texture_desc(destination);
if (!destination_status.ok()) {
return destination_status;
}
if (!has_texture_usage(source.usage, TextureUsage::render_target) if (!has_texture_usage(source.usage, TextureUsage::render_target)
|| !has_texture_usage(destination.usage, TextureUsage::render_target)) { || !has_texture_usage(destination.usage, TextureUsage::render_target)) {
return pp::foundation::Status::invalid_argument("blit endpoints must be render targets"); return pp::foundation::Status::invalid_argument("blit endpoints must be render targets");
@@ -795,14 +810,14 @@ pp::foundation::Status validate_blit_descs(TextureDesc source, TextureDesc desti
return pp::foundation::Status::invalid_argument("blit endpoints must use matching texture formats"); return pp::foundation::Status::invalid_argument("blit endpoints must use matching texture formats");
} }
const auto source_status = texture_byte_size(source); const auto source_bytes = texture_byte_size(source);
if (!source_status.ok()) { if (!source_bytes.ok()) {
return source_status.status(); return source_bytes.status();
} }
const auto destination_status = texture_byte_size(destination); const auto destination_bytes = texture_byte_size(destination);
if (!destination_status.ok()) { if (!destination_bytes.ok()) {
return destination_status.status(); return destination_bytes.status();
} }
return pp::foundation::Status::success(); return pp::foundation::Status::success();

View File

@@ -1132,14 +1132,30 @@ void computes_frame_capture_byte_sizes(pp::tests::Harness& h)
.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,
}; };
const TextureDesc unsupported_usage_desc {
.extent = Extent2D { .width = 16, .height = 8 },
.format = TextureFormat::rgba8,
.usage = TextureUsage::render_target | TextureUsage::readback_source | static_cast<TextureUsage>(1U << 31U),
};
const TextureDesc unknown_format_desc {
.extent = Extent2D { .width = 16, .height = 8 },
.format = static_cast<TextureFormat>(255),
.usage = TextureUsage::render_target | TextureUsage::readback_source,
};
const auto capture = frame_capture_byte_size(target_desc); const auto capture = frame_capture_byte_size(target_desc);
const auto non_target = frame_capture_byte_size(texture_desc); const auto non_target = frame_capture_byte_size(texture_desc);
const auto unsupported_usage = frame_capture_byte_size(unsupported_usage_desc);
const auto unknown_format = frame_capture_byte_size(unknown_format_desc);
PP_EXPECT(h, capture.ok()); PP_EXPECT(h, capture.ok());
PP_EXPECT(h, capture.value() == 512U); PP_EXPECT(h, capture.value() == 512U);
PP_EXPECT(h, !non_target.ok()); PP_EXPECT(h, !non_target.ok());
PP_EXPECT(h, non_target.status().code == StatusCode::invalid_argument); PP_EXPECT(h, non_target.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !unsupported_usage.ok());
PP_EXPECT(h, unsupported_usage.status().code == StatusCode::invalid_argument);
PP_EXPECT(h, !unknown_format.ok());
PP_EXPECT(h, unknown_format.status().code == StatusCode::invalid_argument);
} }
void validates_blit_contract(pp::tests::Harness& h) void validates_blit_contract(pp::tests::Harness& h)
@@ -1159,6 +1175,16 @@ void validates_blit_contract(pp::tests::Harness& h)
.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,
}; };
const TextureDesc unknown_format_target_desc {
.extent = Extent2D { .width = 16, .height = 8 },
.format = static_cast<TextureFormat>(255),
.usage = TextureUsage::render_target | TextureUsage::copy_source | TextureUsage::copy_destination,
};
const TextureDesc unsupported_usage_target_desc {
.extent = Extent2D { .width = 16, .height = 8 },
.format = TextureFormat::rgba8,
.usage = TextureUsage::render_target | TextureUsage::copy_source | TextureUsage::copy_destination | static_cast<TextureUsage>(1U << 31U),
};
PP_EXPECT(h, validate_blit_descs(target_desc, target_desc).ok()); PP_EXPECT(h, validate_blit_descs(target_desc, target_desc).ok());
PP_EXPECT(h, validate_blit_filter(BlitFilter::nearest).ok()); PP_EXPECT(h, validate_blit_filter(BlitFilter::nearest).ok());
@@ -1167,12 +1193,18 @@ void validates_blit_contract(pp::tests::Harness& h)
const auto non_target = validate_blit_descs(texture_desc, target_desc); const auto non_target = validate_blit_descs(texture_desc, target_desc);
const auto mismatched_format = validate_blit_descs(target_desc, r8_target_desc); const auto mismatched_format = validate_blit_descs(target_desc, r8_target_desc);
const auto unknown_format = validate_blit_descs(unknown_format_target_desc, unknown_format_target_desc);
const auto unsupported_usage = validate_blit_descs(unsupported_usage_target_desc, target_desc);
const auto bad_filter = validate_blit_filter(static_cast<BlitFilter>(255)); const auto bad_filter = validate_blit_filter(static_cast<BlitFilter>(255));
PP_EXPECT(h, !non_target.ok()); PP_EXPECT(h, !non_target.ok());
PP_EXPECT(h, non_target.code == StatusCode::invalid_argument); PP_EXPECT(h, non_target.code == StatusCode::invalid_argument);
PP_EXPECT(h, !mismatched_format.ok()); PP_EXPECT(h, !mismatched_format.ok());
PP_EXPECT(h, mismatched_format.code == StatusCode::invalid_argument); PP_EXPECT(h, mismatched_format.code == StatusCode::invalid_argument);
PP_EXPECT(h, !unknown_format.ok());
PP_EXPECT(h, unknown_format.code == StatusCode::invalid_argument);
PP_EXPECT(h, !unsupported_usage.ok());
PP_EXPECT(h, unsupported_usage.code == StatusCode::invalid_argument);
PP_EXPECT(h, !bad_filter.ok()); PP_EXPECT(h, !bad_filter.ok());
PP_EXPECT(h, bad_filter.code == StatusCode::invalid_argument); PP_EXPECT(h, bad_filter.code == StatusCode::invalid_argument);
PP_EXPECT(h, blit_filter_name(static_cast<BlitFilter>(255)) == std::string_view("unknown")); PP_EXPECT(h, blit_filter_name(static_cast<BlitFilter>(255)) == std::string_view("unknown"));