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) if(PP_ENABLE_OPENGL)
add_library(pp_renderer_gl STATIC add_library(pp_renderer_gl STATIC
src/renderer_gl/command_plan.cpp
src/renderer_gl/opengl_capabilities.cpp src/renderer_gl/opengl_capabilities.cpp
src/renderer_gl/shader_bindings.cpp) src/renderer_gl/shader_bindings.cpp)
target_include_directories(pp_renderer_gl 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 The Windows entrypoint also consumes backend-owned generic OpenGL
error-code/info-string tokens and WGL core-context/pixel-format attribute error-code/info-string tokens and WGL core-context/pixel-format attribute
catalogs. 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, Desktop VR drawing also consumes backend-owned scissor/depth/blend state,
depth clear masks, active texture units, and fallback 2D texture unbind depth clear masks, active texture units, and fallback 2D texture unbind
targets while retaining the existing VR SDK/platform bridge shape. 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. overloads.
The Windows entrypoint now delegates generic OpenGL error-code/info-string The Windows entrypoint now delegates generic OpenGL error-code/info-string
tokens and WGL core-context/pixel-format attribute catalogs to `pp_renderer_gl`. 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 The existing renderer classes are not yet fully
behind the renderer interfaces. behind the renderer interfaces.
@@ -835,6 +840,11 @@ Results:
uniform catalog validation covers the 43 legacy uniform uniform catalog validation covers the 43 legacy uniform
names used by `Shader`, preserves the legacy hash ids, and rejects empty, names used by `Shader`, preserves the legacy hash ids, and rejects empty,
unnamed, null-name, mismatched-hash, and duplicate-name catalogs. 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 - PowerShell analyze automation returns JSON summaries and includes the shader
validation target and renderer-boundary guard. validation target and renderer-boundary guard.
- `windows-msvc-vcpkg-headless` configured through the Visual Studio bundled - `windows-msvc-vcpkg-headless` configured through the Visual Studio bundled

View File

@@ -1,7 +1,7 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
[string[]]$Presets = @("android-arm64"), [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" $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) add_test(NAME pp_renderer_gl_capabilities_tests COMMAND pp_renderer_gl_capabilities_tests)
set_tests_properties(pp_renderer_gl_capabilities_tests PROPERTIES set_tests_properties(pp_renderer_gl_capabilities_tests PROPERTIES
LABELS "renderer;desktop-fast") 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() endif()
add_executable(pp_paint_renderer_compositor_tests 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();
}