Plan recorded renderer commands for OpenGL

This commit is contained in:
2026-06-02 20:45:03 +02:00
parent cc33fbdde2
commit ce33eaaef2
8 changed files with 441 additions and 1 deletions

View File

@@ -166,6 +166,7 @@ target_link_libraries(pp_renderer_api
if(PP_ENABLE_OPENGL)
add_library(pp_renderer_gl STATIC
src/renderer_gl/command_plan.cpp
src/renderer_gl/opengl_capabilities.cpp
src/renderer_gl/shader_bindings.cpp)
target_include_directories(pp_renderer_gl

View File

@@ -269,6 +269,11 @@ Known local toolchain state:
The Windows entrypoint also consumes backend-owned generic OpenGL
error-code/info-string tokens and WGL core-context/pixel-format attribute
catalogs.
The headless OpenGL command planner consumes `pp_renderer_api` recorded
commands and maps render-pass clear masks/values, viewport/scissor state,
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
blit filters into GL-facing planned command data while rejecting unsupported
enum tokens before a real GL context is needed.
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.

View File

@@ -528,6 +528,11 @@ filters/wraps, and render-target formats are resolved through backend-owned
overloads.
The Windows entrypoint now delegates generic OpenGL error-code/info-string
tokens and WGL core-context/pixel-format attribute catalogs to `pp_renderer_gl`.
The headless OpenGL command planner now consumes `pp_renderer_api` recorded
commands and maps render-pass clear masks/values, viewport/scissor state,
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.
The existing renderer classes are not yet fully
behind the renderer interfaces.
@@ -835,6 +840,11 @@ Results:
uniform catalog validation covers the 43 legacy uniform
names used by `Shader`, preserves the legacy hash ids, and rejects empty,
unnamed, null-name, mismatched-hash, and duplicate-name catalogs.
- `pp_renderer_gl_command_plan_tests` covers the headless OpenGL command
planner for recorded render-pass clear masks/values, viewport/scissor state,
blend/depth/sampler state, texture format mapping, mesh/draw primitive modes,
draw counts, blit filters, planned command names, and unsupported enum
rejection.
- PowerShell analyze automation returns JSON summaries and includes the shader
validation target and renderer-boundary guard.
- `windows-msvc-vcpkg-headless` configured through the Visual Studio bundled

View File

@@ -1,7 +1,7 @@
[CmdletBinding()]
param(
[string[]]$Presets = @("android-arm64"),
[string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_renderer_gl", "pp_paint_renderer", "pp_ui_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_event_tests", "pp_foundation_log_tests", "pp_foundation_parse_tests", "pp_foundation_task_queue_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_assets_image_metadata_tests", "pp_assets_image_pixels_tests", "pp_assets_ppi_header_tests", "pp_assets_settings_document_tests", "pp_paint_brush_tests", "pp_paint_blend_tests", "pp_paint_stroke_tests", "pp_paint_stroke_script_tests", "pp_document_tests", "pp_document_ppi_import_tests", "pp_document_ppi_export_tests", "pp_renderer_api_tests", "pp_renderer_gl_capabilities_tests", "pp_paint_renderer_compositor_tests", "pp_ui_core_color_tests", "pp_ui_core_layout_value_tests", "pp_ui_core_layout_xml_tests")
[string[]]$Targets = @("pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_renderer_gl", "pp_paint_renderer", "pp_ui_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_event_tests", "pp_foundation_log_tests", "pp_foundation_parse_tests", "pp_foundation_task_queue_tests", "pp_foundation_trace_tests", "pp_assets_image_format_tests", "pp_assets_image_metadata_tests", "pp_assets_image_pixels_tests", "pp_assets_ppi_header_tests", "pp_assets_settings_document_tests", "pp_paint_brush_tests", "pp_paint_blend_tests", "pp_paint_stroke_tests", "pp_paint_stroke_script_tests", "pp_document_tests", "pp_document_ppi_import_tests", "pp_document_ppi_export_tests", "pp_renderer_api_tests", "pp_renderer_gl_capabilities_tests", "pp_renderer_gl_command_plan_tests", "pp_paint_renderer_compositor_tests", "pp_ui_core_color_tests", "pp_ui_core_layout_value_tests", "pp_ui_core_layout_xml_tests")
)
$ErrorActionPreference = "Stop"

View File

@@ -0,0 +1,172 @@
#include "renderer_gl/command_plan.h"
namespace pp::renderer::gl {
namespace {
[[nodiscard]] bool texture_format_supported(OpenGlRendererTextureFormat format) noexcept
{
return format.internal_format != 0U
&& format.pixel_format != 0U
&& format.component_type != 0U
&& format.bytes_per_pixel != 0U;
}
[[nodiscard]] bool requires_render_pass(pp::renderer::RecordedRenderCommandKind kind) noexcept
{
switch (kind) {
case pp::renderer::RecordedRenderCommandKind::set_viewport:
case pp::renderer::RecordedRenderCommandKind::set_scissor:
case pp::renderer::RecordedRenderCommandKind::set_blend_state:
case pp::renderer::RecordedRenderCommandKind::set_depth_state:
case pp::renderer::RecordedRenderCommandKind::bind_shader:
case pp::renderer::RecordedRenderCommandKind::set_shader_uniform:
case pp::renderer::RecordedRenderCommandKind::bind_texture:
case pp::renderer::RecordedRenderCommandKind::bind_sampler:
case pp::renderer::RecordedRenderCommandKind::bind_mesh:
case pp::renderer::RecordedRenderCommandKind::draw:
return true;
default:
return false;
}
}
}
const char* planned_command_kind_name(OpenGlPlannedCommandKind kind) noexcept
{
switch (kind) {
case OpenGlPlannedCommandKind::unknown:
return "unknown";
case OpenGlPlannedCommandKind::begin_render_pass:
return "begin_render_pass";
case OpenGlPlannedCommandKind::set_viewport:
return "set_viewport";
case OpenGlPlannedCommandKind::set_scissor:
return "set_scissor";
case OpenGlPlannedCommandKind::set_blend_state:
return "set_blend_state";
case OpenGlPlannedCommandKind::set_depth_state:
return "set_depth_state";
case OpenGlPlannedCommandKind::bind_texture:
return "bind_texture";
case OpenGlPlannedCommandKind::bind_sampler:
return "bind_sampler";
case OpenGlPlannedCommandKind::bind_mesh:
return "bind_mesh";
case OpenGlPlannedCommandKind::draw:
return "draw";
case OpenGlPlannedCommandKind::blit_render_target:
return "blit_render_target";
case OpenGlPlannedCommandKind::end_render_pass:
return "end_render_pass";
case OpenGlPlannedCommandKind::trace:
return "trace";
case OpenGlPlannedCommandKind::passthrough:
return "passthrough";
}
return "unknown";
}
OpenGlPlannedCommand plan_recorded_render_command(pp::renderer::RecordedRenderCommand command) noexcept
{
OpenGlPlannedCommand planned {};
planned.requires_render_pass = requires_render_pass(command.kind);
planned.supported = true;
switch (command.kind) {
case pp::renderer::RecordedRenderCommandKind::begin_render_pass:
planned.kind = OpenGlPlannedCommandKind::begin_render_pass;
planned.clear_mask = clear_mask_for_render_pass(pp::renderer::RenderPassDesc {
.clear_color_enabled = command.clear_color_enabled,
.clear_color = command.clear_color,
.clear_depth_enabled = command.clear_depth_enabled,
.clear_depth = command.clear_depth,
.clear_stencil_enabled = command.clear_stencil_enabled,
.clear_stencil = command.clear_stencil,
});
planned.clear_values = clear_values_for_render_pass(pp::renderer::RenderPassDesc {
.clear_color_enabled = command.clear_color_enabled,
.clear_color = command.clear_color,
.clear_depth_enabled = command.clear_depth_enabled,
.clear_depth = command.clear_depth,
.clear_stencil_enabled = command.clear_stencil_enabled,
.clear_stencil = command.clear_stencil,
});
planned.texture_format = texture_format_for_renderer_format(command.target_desc.format);
planned.supported = texture_format_supported(planned.texture_format);
break;
case pp::renderer::RecordedRenderCommandKind::set_viewport:
planned.kind = OpenGlPlannedCommandKind::set_viewport;
planned.viewport = viewport_for_renderer_viewport(command.viewport);
break;
case pp::renderer::RecordedRenderCommandKind::set_scissor:
planned.kind = OpenGlPlannedCommandKind::set_scissor;
planned.scissor = scissor_rect_for_renderer_scissor(command.scissor);
break;
case pp::renderer::RecordedRenderCommandKind::set_blend_state:
planned.kind = OpenGlPlannedCommandKind::set_blend_state;
planned.blend = blend_state_for_renderer_blend_state(command.blend_state);
planned.supported = planned.blend.supported;
break;
case pp::renderer::RecordedRenderCommandKind::set_depth_state:
planned.kind = OpenGlPlannedCommandKind::set_depth_state;
planned.depth = depth_state_for_renderer_depth_state(command.depth_state);
planned.supported = planned.depth.supported;
break;
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);
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;
break;
case pp::renderer::RecordedRenderCommandKind::bind_mesh:
planned.kind = OpenGlPlannedCommandKind::bind_mesh;
planned.primitive_mode = primitive_mode_for_renderer_topology(command.mesh_desc.topology);
planned.supported = planned.primitive_mode != 0U;
break;
case pp::renderer::RecordedRenderCommandKind::draw:
planned.kind = OpenGlPlannedCommandKind::draw;
planned.primitive_mode = primitive_mode_for_renderer_topology(command.mesh_desc.topology);
planned.draw_vertex_count = command.draw_desc.vertex_count;
planned.draw_index_count = command.draw_desc.index_count;
planned.supported = planned.primitive_mode != 0U;
break;
case pp::renderer::RecordedRenderCommandKind::blit_render_target:
planned.kind = OpenGlPlannedCommandKind::blit_render_target;
planned.blit_filter = blit_filter_for_renderer_filter(command.blit_filter);
planned.supported = planned.blit_filter.supported;
break;
case pp::renderer::RecordedRenderCommandKind::end_render_pass:
planned.kind = OpenGlPlannedCommandKind::end_render_pass;
break;
case pp::renderer::RecordedRenderCommandKind::trace_marker:
case pp::renderer::RecordedRenderCommandKind::trace_begin_scope:
case pp::renderer::RecordedRenderCommandKind::trace_end_scope:
planned.kind = OpenGlPlannedCommandKind::trace;
break;
case pp::renderer::RecordedRenderCommandKind::bind_shader:
case pp::renderer::RecordedRenderCommandKind::set_shader_uniform:
case pp::renderer::RecordedRenderCommandKind::upload_texture:
case pp::renderer::RecordedRenderCommandKind::generate_mipmaps:
case pp::renderer::RecordedRenderCommandKind::transition_texture:
case pp::renderer::RecordedRenderCommandKind::copy_texture:
case pp::renderer::RecordedRenderCommandKind::read_texture:
case pp::renderer::RecordedRenderCommandKind::capture_frame:
planned.kind = OpenGlPlannedCommandKind::passthrough;
break;
default:
planned.kind = OpenGlPlannedCommandKind::unknown;
planned.supported = false;
break;
}
return planned;
}
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include "renderer_api/recording_renderer.h"
#include "renderer_gl/opengl_capabilities.h"
#include <cstdint>
namespace pp::renderer::gl {
enum class OpenGlPlannedCommandKind : std::uint8_t {
unknown,
begin_render_pass,
set_viewport,
set_scissor,
set_blend_state,
set_depth_state,
bind_texture,
bind_sampler,
bind_mesh,
draw,
blit_render_target,
end_render_pass,
trace,
passthrough,
};
struct OpenGlPlannedCommand {
OpenGlPlannedCommandKind kind = OpenGlPlannedCommandKind::unknown;
std::uint32_t clear_mask = 0;
OpenGlClearValues clear_values;
OpenGlViewportRect viewport;
OpenGlScissorRect scissor;
OpenGlBlendState blend;
OpenGlDepthState depth;
OpenGlSamplerState sampler;
OpenGlRendererTextureFormat texture_format;
OpenGlEnumMapping blit_filter;
std::uint32_t primitive_mode = 0;
std::uint32_t draw_vertex_count = 0;
std::uint32_t draw_index_count = 0;
bool requires_render_pass = false;
bool supported = false;
};
[[nodiscard]] const char* planned_command_kind_name(OpenGlPlannedCommandKind kind) noexcept;
[[nodiscard]] OpenGlPlannedCommand plan_recorded_render_command(
pp::renderer::RecordedRenderCommand command) noexcept;
}

View File

@@ -206,6 +206,16 @@ if(TARGET pp_renderer_gl)
add_test(NAME pp_renderer_gl_capabilities_tests COMMAND pp_renderer_gl_capabilities_tests)
set_tests_properties(pp_renderer_gl_capabilities_tests PROPERTIES
LABELS "renderer;desktop-fast")
add_executable(pp_renderer_gl_command_plan_tests
renderer_gl/command_plan_tests.cpp)
target_link_libraries(pp_renderer_gl_command_plan_tests PRIVATE
pp_renderer_gl
pp_test_harness)
add_test(NAME pp_renderer_gl_command_plan_tests COMMAND pp_renderer_gl_command_plan_tests)
set_tests_properties(pp_renderer_gl_command_plan_tests PROPERTIES
LABELS "renderer;desktop-fast")
endif()
add_executable(pp_paint_renderer_compositor_tests

View File

@@ -0,0 +1,193 @@
#include "renderer_gl/command_plan.h"
#include "test_harness.h"
#include <string_view>
namespace {
void maps_render_pass_and_state_commands(pp::tests::Harness& h)
{
const auto begin = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::begin_render_pass,
.target_desc = pp::renderer::TextureDesc {
.extent = pp::renderer::Extent2D { .width = 64U, .height = 32U },
.format = pp::renderer::TextureFormat::rgba8,
},
.clear_color_enabled = true,
.clear_color = pp::renderer::ClearColor { .r = 0.25F, .g = 0.5F, .b = 0.75F, .a = 1.0F },
.clear_depth_enabled = true,
.clear_depth = 0.875F,
.clear_stencil_enabled = true,
.clear_stencil = 3U,
});
const auto viewport = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_viewport,
.viewport = pp::renderer::Viewport { .x = 2, .y = 4, .width = 32U, .height = 16U },
});
const auto scissor = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_scissor,
.scissor = pp::renderer::ScissorRect { .enabled = true, .x = 3, .y = 5, .width = 8U, .height = 6U },
});
const auto blend = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_blend_state,
.blend_state = pp::renderer::BlendState {
.enabled = true,
.source_color = pp::renderer::BlendFactor::source_alpha,
.destination_color = pp::renderer::BlendFactor::one_minus_source_alpha,
},
});
const auto depth = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_depth_state,
.depth_state = pp::renderer::DepthState {
.test_enabled = true,
.write_enabled = true,
.compare = pp::renderer::CompareOp::greater,
},
});
PP_EXPECT(h, begin.supported);
PP_EXPECT(h, begin.kind == pp::renderer::gl::OpenGlPlannedCommandKind::begin_render_pass);
PP_EXPECT(h, begin.clear_mask == 0x00004500U);
PP_EXPECT(h, begin.clear_values.color[2] == 0.75F);
PP_EXPECT(h, begin.clear_values.depth == 0.875F);
PP_EXPECT(h, begin.clear_values.stencil == 3U);
PP_EXPECT(h, begin.texture_format.internal_format == 0x8058U);
PP_EXPECT(h, !begin.requires_render_pass);
PP_EXPECT(h, viewport.supported);
PP_EXPECT(h, viewport.requires_render_pass);
PP_EXPECT(h, viewport.viewport.x == 2);
PP_EXPECT(h, viewport.viewport.width == 32);
PP_EXPECT(h, scissor.supported);
PP_EXPECT(h, scissor.scissor.enabled == 1U);
PP_EXPECT(h, scissor.scissor.height == 6);
PP_EXPECT(h, blend.supported);
PP_EXPECT(h, blend.blend.enabled == 1U);
PP_EXPECT(h, blend.blend.source_color_factor == 0x0302U);
PP_EXPECT(h, depth.supported);
PP_EXPECT(h, depth.depth.test_enabled == 1U);
PP_EXPECT(h, depth.depth.compare_function == 0x0204U);
}
void maps_binding_draw_and_blit_commands(pp::tests::Harness& h)
{
const auto texture = 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 = 16U, .height = 16U },
.format = pp::renderer::TextureFormat::depth24_stencil8,
},
});
const auto sampler = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
.sampler_desc = pp::renderer::SamplerDesc {
.min_filter = pp::renderer::SamplerFilter::nearest,
.mag_filter = pp::renderer::SamplerFilter::linear,
.mip_filter = pp::renderer::SamplerFilter::linear,
.address_u = pp::renderer::SamplerAddressMode::repeat,
.address_v = pp::renderer::SamplerAddressMode::mirrored_repeat,
.address_w = pp::renderer::SamplerAddressMode::clamp_to_border,
},
});
const auto mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_mesh,
.mesh_desc = pp::renderer::MeshDesc { .topology = pp::renderer::PrimitiveTopology::triangle_strip },
});
const auto draw = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::draw,
.mesh_desc = pp::renderer::MeshDesc { .topology = pp::renderer::PrimitiveTopology::lines },
.draw_desc = pp::renderer::DrawDesc { .vertex_count = 4U, .index_count = 2U },
});
const auto blit = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::blit_render_target,
.blit_filter = pp::renderer::BlitFilter::linear,
});
PP_EXPECT(h, texture.supported);
PP_EXPECT(h, texture.requires_render_pass);
PP_EXPECT(h, texture.texture_format.internal_format == 0x88F0U);
PP_EXPECT(h, sampler.supported);
PP_EXPECT(h, sampler.sampler.min_filter == 0x2702U);
PP_EXPECT(h, sampler.sampler.wrap_t == 0x8370U);
PP_EXPECT(h, mesh.supported);
PP_EXPECT(h, mesh.primitive_mode == 0x0005U);
PP_EXPECT(h, draw.supported);
PP_EXPECT(h, draw.primitive_mode == 0x0001U);
PP_EXPECT(h, draw.draw_vertex_count == 4U);
PP_EXPECT(h, draw.draw_index_count == 2U);
PP_EXPECT(h, blit.supported);
PP_EXPECT(h, !blit.requires_render_pass);
PP_EXPECT(h, blit.blit_filter.value == 0x2601U);
}
void rejects_unsupported_command_tokens(pp::tests::Harness& h)
{
const auto bad_blend = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_blend_state,
.blend_state = pp::renderer::BlendState {
.source_color = static_cast<pp::renderer::BlendFactor>(255U),
},
});
const auto bad_depth = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::set_depth_state,
.depth_state = pp::renderer::DepthState {
.compare = static_cast<pp::renderer::CompareOp>(255U),
},
});
const auto bad_sampler = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::bind_sampler,
.sampler_desc = pp::renderer::SamplerDesc {
.address_u = static_cast<pp::renderer::SamplerAddressMode>(255U),
},
});
const auto bad_mesh = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::draw,
.mesh_desc = pp::renderer::MeshDesc {
.topology = static_cast<pp::renderer::PrimitiveTopology>(255U),
},
});
const auto bad_blit = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = pp::renderer::RecordedRenderCommandKind::blit_render_target,
.blit_filter = static_cast<pp::renderer::BlitFilter>(255U),
});
const auto unknown = pp::renderer::gl::plan_recorded_render_command(pp::renderer::RecordedRenderCommand {
.kind = static_cast<pp::renderer::RecordedRenderCommandKind>(255U),
});
PP_EXPECT(h, !bad_blend.supported);
PP_EXPECT(h, bad_blend.blend.source_color_factor == 0U);
PP_EXPECT(h, !bad_depth.supported);
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_mesh.supported);
PP_EXPECT(h, bad_mesh.primitive_mode == 0U);
PP_EXPECT(h, !bad_blit.supported);
PP_EXPECT(h, bad_blit.blit_filter.value == 0U);
PP_EXPECT(h, !unknown.supported);
PP_EXPECT(h, unknown.kind == pp::renderer::gl::OpenGlPlannedCommandKind::unknown);
}
void names_planned_command_kinds(pp::tests::Harness& h)
{
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
pp::renderer::gl::OpenGlPlannedCommandKind::begin_render_pass)
== std::string_view("begin_render_pass"));
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
pp::renderer::gl::OpenGlPlannedCommandKind::passthrough)
== std::string_view("passthrough"));
PP_EXPECT(h, pp::renderer::gl::planned_command_kind_name(
static_cast<pp::renderer::gl::OpenGlPlannedCommandKind>(255U))
== std::string_view("unknown"));
}
}
int main()
{
pp::tests::Harness harness;
harness.run("maps_render_pass_and_state_commands", maps_render_pass_and_state_commands);
harness.run("maps_binding_draw_and_blit_commands", maps_binding_draw_and_blit_commands);
harness.run("rejects_unsupported_command_tokens", rejects_unsupported_command_tokens);
harness.run("names_planned_command_kinds", names_planned_command_kinds);
return harness.finish();
}