Validate OpenGL texture binding slots
This commit is contained in:
@@ -275,13 +275,16 @@ Known local toolchain state:
|
||||
blit filters into GL-facing planned command data while rejecting unsupported
|
||||
enum tokens before a real GL context is needed. It also plans whole recorded
|
||||
command streams, preserving per-command planned data while counting render
|
||||
passes, draws, shader binds, shader uniforms, texture uploads, mipmap
|
||||
generation, texture transitions, texture copies, texture readbacks, frame
|
||||
captures, passthrough commands, trace commands, unsupported commands, and
|
||||
render-pass ordering errors such as state changes outside a pass, nested
|
||||
passes, and unclosed passes. It also validates executable command
|
||||
dependencies, including shader-before-uniform and shader-plus-mesh before
|
||||
draw within each render pass.
|
||||
passes, draws, shader binds, shader uniforms, texture/sampler binds, texture
|
||||
uploads, mipmap generation, texture transitions, texture copies, texture
|
||||
readbacks, frame captures, passthrough commands, trace commands, unsupported
|
||||
commands, and render-pass ordering errors such as state changes outside a
|
||||
pass, nested passes, and unclosed passes. It also validates executable
|
||||
command dependencies, including shader-before-uniform and shader-plus-mesh
|
||||
before draw within each render pass, and rejects invalid texture/sampler bind
|
||||
slots in malformed recorded streams. `pano_cli record-render` emits the
|
||||
OpenGL plan texture/sampler bind counts so automation can assert backend
|
||||
interpretation without an OpenGL context.
|
||||
Desktop VR drawing also consumes backend-owned scissor/depth/blend state,
|
||||
depth clear masks, active texture units, and fallback 2D texture unbind
|
||||
targets while retaining the existing VR SDK/platform bridge shape.
|
||||
|
||||
@@ -534,13 +534,14 @@ blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
||||
blit filters into GL-facing planned command data with explicit unsupported-token
|
||||
rejection before a runtime GL context is needed. It also plans whole recorded
|
||||
command streams, preserving per-command planned data while counting render
|
||||
passes, draws, shader binds, shader uniforms, texture uploads, mipmap
|
||||
generation, texture transitions, texture copies, texture readbacks, frame
|
||||
captures, passthrough commands, trace commands, unsupported commands, and
|
||||
render-pass ordering errors such as state changes outside a pass, nested
|
||||
passes, and unclosed passes. It also validates executable command dependencies,
|
||||
including shader-before-uniform and shader-plus-mesh before draw within each
|
||||
render pass.
|
||||
passes, draws, shader binds, shader uniforms, texture/sampler binds, texture
|
||||
uploads, mipmap generation, texture transitions, texture copies, texture
|
||||
readbacks, frame captures, passthrough commands, trace commands, unsupported
|
||||
commands, and render-pass ordering errors such as state changes outside a pass,
|
||||
nested passes, and unclosed passes. It also validates executable command
|
||||
dependencies, including shader-before-uniform and shader-plus-mesh before draw
|
||||
within each render pass, and rejects invalid texture/sampler bind slots in
|
||||
malformed recorded streams.
|
||||
The existing renderer classes are not yet fully
|
||||
behind the renderer interfaces.
|
||||
|
||||
|
||||
@@ -191,12 +191,16 @@ OpenGlPlannedCommand plan_recorded_render_command(pp::renderer::RecordedRenderCo
|
||||
case pp::renderer::RecordedRenderCommandKind::bind_texture:
|
||||
planned.kind = OpenGlPlannedCommandKind::bind_texture;
|
||||
planned.texture_format = texture_format_for_renderer_format(command.texture_desc.format);
|
||||
planned.supported = texture_format_supported(planned.texture_format);
|
||||
planned.texture_slot = command.texture_slot;
|
||||
planned.supported = texture_format_supported(planned.texture_format)
|
||||
&& planned.texture_slot < pp::renderer::max_texture_slots;
|
||||
break;
|
||||
case pp::renderer::RecordedRenderCommandKind::bind_sampler:
|
||||
planned.kind = OpenGlPlannedCommandKind::bind_sampler;
|
||||
planned.sampler = sampler_state_for_renderer_sampler_desc(command.sampler_desc);
|
||||
planned.supported = planned.sampler.supported;
|
||||
planned.sampler_slot = command.sampler_slot;
|
||||
planned.supported = planned.sampler.supported
|
||||
&& planned.sampler_slot < pp::renderer::max_texture_slots;
|
||||
break;
|
||||
case pp::renderer::RecordedRenderCommandKind::bind_mesh:
|
||||
planned.kind = OpenGlPlannedCommandKind::bind_mesh;
|
||||
@@ -346,6 +350,18 @@ OpenGlCommandPlan plan_recorded_render_commands(
|
||||
record_dependency_error(plan, index);
|
||||
}
|
||||
break;
|
||||
case OpenGlPlannedCommandKind::bind_texture:
|
||||
++plan.texture_bind_command_count;
|
||||
if (!in_render_pass) {
|
||||
record_render_pass_order_error(plan, index);
|
||||
}
|
||||
break;
|
||||
case OpenGlPlannedCommandKind::bind_sampler:
|
||||
++plan.sampler_bind_command_count;
|
||||
if (!in_render_pass) {
|
||||
record_render_pass_order_error(plan, index);
|
||||
}
|
||||
break;
|
||||
case OpenGlPlannedCommandKind::bind_mesh:
|
||||
if (!in_render_pass) {
|
||||
record_render_pass_order_error(plan, index);
|
||||
|
||||
@@ -53,6 +53,8 @@ struct OpenGlPlannedCommand {
|
||||
pp::renderer::ReadbackRegion readback_region;
|
||||
pp::renderer::ReadbackRegion source_region;
|
||||
pp::renderer::ReadbackRegion destination_region;
|
||||
std::uint32_t texture_slot = 0;
|
||||
std::uint32_t sampler_slot = 0;
|
||||
std::uint64_t upload_bytes = 0;
|
||||
std::uint32_t generated_mip_levels = 0;
|
||||
std::uint64_t generated_mip_bytes = 0;
|
||||
@@ -79,6 +81,8 @@ struct OpenGlCommandPlan {
|
||||
std::uint32_t draw_command_count = 0;
|
||||
std::uint32_t shader_bind_command_count = 0;
|
||||
std::uint32_t uniform_command_count = 0;
|
||||
std::uint32_t texture_bind_command_count = 0;
|
||||
std::uint32_t sampler_bind_command_count = 0;
|
||||
std::uint32_t upload_command_count = 0;
|
||||
std::uint32_t mipmap_command_count = 0;
|
||||
std::uint32_t transition_command_count = 0;
|
||||
|
||||
@@ -384,7 +384,7 @@ if(TARGET pano_cli)
|
||||
COMMAND pano_cli record-render --width 32 --height 16)
|
||||
set_tests_properties(pano_cli_record_render_smoke PROPERTIES
|
||||
LABELS "renderer;integration;desktop-fast"
|
||||
PASS_REGULAR_EXPRESSION "\"backend\":\"recording\".*\"framebufferFetch\":false.*\"explicitTextureTransitions\":true.*\"textureCopy\":true.*\"renderTargetBlit\":true.*\"frameCapture\":true.*\"float16RenderTargets\":false.*\"float32RenderTargets\":false.*\"width\":32.*\"height\":16.*\"createdResources\":7.*\"exercisedClearReset\":false.*\"clearRejectedOrphanedTraceEnd\":false.*\"clearReusedRenderPass\":false.*\"labeledCommandDescriptors\":16.*\"commands\":25.*\"openGlPlan\":.*\"available\":true.*\"supported\":true.*\"commands\":25.*\"renderPasses\":1.*\"drawCommands\":1.*\"shaderBindCommands\":1.*\"uniformCommands\":1.*\"uploadCommands\":1.*\"mipmapCommands\":1.*\"transitionCommands\":4.*\"copyCommands\":1.*\"readbackCommands\":1.*\"captureCommands\":1.*\"passthroughCommands\":0.*\"traceCommands\":3.*\"unsupportedCommands\":0.*\"renderPassOrderErrors\":0.*\"dependencyErrors\":0.*\"endedInRenderPass\":false.*\"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.*\"mipmapCommands\":1.*\"mipmapLevels\":3.*\"mipmapBytes\":84.*\"transitionCommands\":4.*\"transitionToUpload\":1.*\"transitionToShaderRead\":2.*\"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\".*\"framebufferFetch\":false.*\"explicitTextureTransitions\":true.*\"textureCopy\":true.*\"renderTargetBlit\":true.*\"frameCapture\":true.*\"float16RenderTargets\":false.*\"float32RenderTargets\":false.*\"width\":32.*\"height\":16.*\"createdResources\":7.*\"exercisedClearReset\":false.*\"clearRejectedOrphanedTraceEnd\":false.*\"clearReusedRenderPass\":false.*\"labeledCommandDescriptors\":16.*\"commands\":25.*\"openGlPlan\":.*\"available\":true.*\"supported\":true.*\"commands\":25.*\"renderPasses\":1.*\"drawCommands\":1.*\"shaderBindCommands\":1.*\"uniformCommands\":1.*\"textureBindCommands\":1.*\"samplerBindCommands\":1.*\"uploadCommands\":1.*\"mipmapCommands\":1.*\"transitionCommands\":4.*\"copyCommands\":1.*\"readbackCommands\":1.*\"captureCommands\":1.*\"passthroughCommands\":0.*\"traceCommands\":3.*\"unsupportedCommands\":0.*\"renderPassOrderErrors\":0.*\"dependencyErrors\":0.*\"endedInRenderPass\":false.*\"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.*\"mipmapCommands\":1.*\"mipmapLevels\":3.*\"mipmapBytes\":84.*\"transitionCommands\":4.*\"transitionToUpload\":1.*\"transitionToShaderRead\":2.*\"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_exercises_clear_reset
|
||||
COMMAND pano_cli record-render --width 32 --height 16 --exercise-clear)
|
||||
|
||||
@@ -164,6 +164,7 @@ void maps_binding_draw_and_blit_commands(pp::tests::Harness& h)
|
||||
.extent = pp::renderer::Extent2D { .width = 16U, .height = 16U },
|
||||
.format = pp::renderer::TextureFormat::depth24_stencil8,
|
||||
},
|
||||
.texture_slot = 3U,
|
||||
});
|
||||
const auto sampler = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
|
||||
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
|
||||
@@ -175,6 +176,7 @@ void maps_binding_draw_and_blit_commands(pp::tests::Harness& h)
|
||||
.address_v = pp::renderer::SamplerAddressMode::mirrored_repeat,
|
||||
.address_w = pp::renderer::SamplerAddressMode::clamp_to_border,
|
||||
},
|
||||
.sampler_slot = 3U,
|
||||
});
|
||||
const auto mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
|
||||
.kind = pp::renderer::RecordedRenderCommandKind::bind_mesh,
|
||||
@@ -191,9 +193,11 @@ void maps_binding_draw_and_blit_commands(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, texture.supported);
|
||||
PP_EXPECT(h, texture.requires_render_pass);
|
||||
PP_EXPECT(h, texture.texture_format.internal_format == 0x88F0U);
|
||||
PP_EXPECT(h, texture.texture_slot == 3U);
|
||||
PP_EXPECT(h, sampler.supported);
|
||||
PP_EXPECT(h, sampler.sampler.min_filter == 0x2702U);
|
||||
PP_EXPECT(h, sampler.sampler.wrap_t == 0x8370U);
|
||||
PP_EXPECT(h, sampler.sampler_slot == 3U);
|
||||
PP_EXPECT(h, mesh.supported);
|
||||
PP_EXPECT(h, mesh.primitive_mode == 0x0005U);
|
||||
PP_EXPECT(h, draw.supported);
|
||||
@@ -321,6 +325,18 @@ void rejects_unsupported_command_tokens(pp::tests::Harness& h)
|
||||
.address_u = static_cast<pp::renderer::SamplerAddressMode>(255U),
|
||||
},
|
||||
});
|
||||
const auto bad_texture_slot = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
|
||||
.kind = pp::renderer::RecordedRenderCommandKind::bind_texture,
|
||||
.texture_desc = pp::renderer::TextureDesc {
|
||||
.extent = pp::renderer::Extent2D { .width = 1U, .height = 1U },
|
||||
.format = pp::renderer::TextureFormat::rgba8,
|
||||
},
|
||||
.texture_slot = pp::renderer::max_texture_slots,
|
||||
});
|
||||
const auto bad_sampler_slot = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
|
||||
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
|
||||
.sampler_slot = pp::renderer::max_texture_slots,
|
||||
});
|
||||
const auto bad_mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
|
||||
.kind = pp::renderer::RecordedRenderCommandKind::draw,
|
||||
.mesh_desc = pp::renderer::MeshDesc {
|
||||
@@ -349,6 +365,10 @@ void rejects_unsupported_command_tokens(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, bad_depth.depth.compare_function == 0U);
|
||||
PP_EXPECT(h, !bad_sampler.supported);
|
||||
PP_EXPECT(h, bad_sampler.sampler.wrap_s == 0U);
|
||||
PP_EXPECT(h, !bad_texture_slot.supported);
|
||||
PP_EXPECT(h, bad_texture_slot.texture_slot == pp::renderer::max_texture_slots);
|
||||
PP_EXPECT(h, !bad_sampler_slot.supported);
|
||||
PP_EXPECT(h, bad_sampler_slot.sampler_slot == pp::renderer::max_texture_slots);
|
||||
PP_EXPECT(h, !bad_mesh.supported);
|
||||
PP_EXPECT(h, bad_mesh.primitive_mode == 0U);
|
||||
PP_EXPECT(h, !bad_blit.supported);
|
||||
@@ -404,6 +424,8 @@ void plans_valid_recorded_command_streams(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, plan.draw_command_count == 1U);
|
||||
PP_EXPECT(h, plan.shader_bind_command_count == 1U);
|
||||
PP_EXPECT(h, plan.uniform_command_count == 1U);
|
||||
PP_EXPECT(h, plan.texture_bind_command_count == 0U);
|
||||
PP_EXPECT(h, plan.sampler_bind_command_count == 0U);
|
||||
PP_EXPECT(h, plan.passthrough_command_count == 0U);
|
||||
PP_EXPECT(h, plan.trace_command_count == 1U);
|
||||
PP_EXPECT(h, plan.unsupported_command_count == 0U);
|
||||
@@ -421,6 +443,39 @@ void plans_valid_recorded_command_streams(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, plan.commands[8].kind == pp::renderer::gl::OpenGlPlannedCommandKind::blit_render_target);
|
||||
}
|
||||
|
||||
void counts_texture_and_sampler_bindings_in_streams(pp::tests::Harness& h)
|
||||
{
|
||||
pp::renderer::RecordedRenderCommand texture_command;
|
||||
texture_command.kind = pp::renderer::RecordedRenderCommandKind::bind_texture;
|
||||
texture_command.texture_desc.format = pp::renderer::TextureFormat::rgba8;
|
||||
texture_command.texture_slot = 2U;
|
||||
|
||||
pp::renderer::RecordedRenderCommand sampler_command;
|
||||
sampler_command.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler;
|
||||
sampler_command.sampler_slot = 2U;
|
||||
|
||||
const std::vector<pp::renderer::RecordedRenderCommand> commands {
|
||||
begin_render_pass_command(),
|
||||
bind_shader_command("shader"),
|
||||
texture_command,
|
||||
sampler_command,
|
||||
bind_mesh_command(),
|
||||
draw_command(),
|
||||
command_with_kind(pp::renderer::RecordedRenderCommandKind::end_render_pass),
|
||||
};
|
||||
|
||||
const auto plan = pp::renderer::gl::plan_recorded_render_commands(commands);
|
||||
|
||||
PP_EXPECT(h, plan.supported);
|
||||
PP_EXPECT(h, plan.texture_bind_command_count == 1U);
|
||||
PP_EXPECT(h, plan.sampler_bind_command_count == 1U);
|
||||
PP_EXPECT(h, plan.unsupported_command_count == 0U);
|
||||
PP_EXPECT(h, plan.render_pass_order_error_count == 0U);
|
||||
PP_EXPECT(h, plan.dependency_error_count == 0U);
|
||||
PP_EXPECT(h, plan.commands[2].texture_slot == 2U);
|
||||
PP_EXPECT(h, plan.commands[3].sampler_slot == 2U);
|
||||
}
|
||||
|
||||
void flags_broken_render_pass_command_order(pp::tests::Harness& h)
|
||||
{
|
||||
const std::vector<pp::renderer::RecordedRenderCommand> outside_pass {
|
||||
@@ -594,6 +649,7 @@ int main()
|
||||
harness.run("rejects_unsupported_command_tokens", rejects_unsupported_command_tokens);
|
||||
harness.run("names_planned_command_kinds", names_planned_command_kinds);
|
||||
harness.run("plans_valid_recorded_command_streams", plans_valid_recorded_command_streams);
|
||||
harness.run("counts_texture_and_sampler_bindings_in_streams", counts_texture_and_sampler_bindings_in_streams);
|
||||
harness.run("flags_broken_render_pass_command_order", flags_broken_render_pass_command_order);
|
||||
harness.run("flags_missing_render_dependencies", flags_missing_render_dependencies);
|
||||
harness.run("tracks_unsupported_commands_in_streams", tracks_unsupported_commands_in_streams);
|
||||
|
||||
@@ -2787,6 +2787,8 @@ int record_render(int argc, char** argv)
|
||||
<< ",\"drawCommands\":" << open_gl_plan.draw_command_count
|
||||
<< ",\"shaderBindCommands\":" << open_gl_plan.shader_bind_command_count
|
||||
<< ",\"uniformCommands\":" << open_gl_plan.uniform_command_count
|
||||
<< ",\"textureBindCommands\":" << open_gl_plan.texture_bind_command_count
|
||||
<< ",\"samplerBindCommands\":" << open_gl_plan.sampler_bind_command_count
|
||||
<< ",\"uploadCommands\":" << open_gl_plan.upload_command_count
|
||||
<< ",\"mipmapCommands\":" << open_gl_plan.mipmap_command_count
|
||||
<< ",\"transitionCommands\":" << open_gl_plan.transition_command_count
|
||||
|
||||
Reference in New Issue
Block a user