Add renderer backend feature reporting
This commit is contained in:
@@ -284,8 +284,9 @@ Known local toolchain state:
|
||||
renderer-boundary guard that reports JSON and fails if active non-backend
|
||||
source code reintroduces raw `GL_*`/`WGL_*` constants outside the allowed
|
||||
legacy OpenGL implementation files.
|
||||
- `pp_renderer_api` exposes a headless `RecordingRenderDevice` that validates
|
||||
backend-owned resource creation, explicit texture usage flags, command order,
|
||||
- `pp_renderer_api` exposes a headless `RecordingRenderDevice` that reports
|
||||
renderer feature flags and validates backend-owned resource creation,
|
||||
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,
|
||||
@@ -297,7 +298,7 @@ Known local toolchain state:
|
||||
frame-capture/blit commands, draw mesh inputs, explicit draw ranges, and
|
||||
records trace markers and scopes without a window or GL context.
|
||||
- `pano_cli record-render` exposes the recording renderer through JSON
|
||||
automation, including render-pass/depth-clear counts, scissor/depth/blend/
|
||||
automation, including backend feature flags, render-pass/depth-clear counts, scissor/depth/blend/
|
||||
shader-uniform/texture-bind/sampler-bind/upload/mipmap-generation/texture-transition/texture-copy/readback/
|
||||
frame-capture/blit command and byte totals, trace marker/scope counts,
|
||||
labeled descriptor counts, backend resource creation counts, plus draw
|
||||
|
||||
@@ -414,7 +414,7 @@ Goal: make OpenGL an implementation detail and establish parity tests before
|
||||
adding new backends.
|
||||
|
||||
Status: started. `pp_renderer_api` exists as a headless renderer-neutral target
|
||||
with explicit texture usage flags, texture descriptor, byte-size, viewport,
|
||||
with renderer feature flags, explicit texture usage flags, texture descriptor, byte-size, viewport,
|
||||
mesh, readback bounds, command context, render device, shader program
|
||||
descriptor, mesh, render target, readback byte-size helpers,
|
||||
texture mip-level validation, resource debug-label validation,
|
||||
@@ -830,7 +830,7 @@ Results:
|
||||
reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL
|
||||
implementation files.
|
||||
- `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict
|
||||
renderer-owned resource factory and
|
||||
renderer feature flags, renderer-owned resource factory and
|
||||
command-order/render-pass-clear/scissor-state/depth-state/blend-state/
|
||||
texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/
|
||||
mipmap-generation/texture-transition/readback/frame-capture/blit validation plus explicit draw
|
||||
@@ -843,7 +843,7 @@ Results:
|
||||
and render-target blits, giving automation a backend-neutral render path that
|
||||
does not require a window or GL context.
|
||||
- `pano_cli record-render` exercises that headless recording renderer and emits
|
||||
JSON command counts, resource creation counts, target dimensions, backend
|
||||
JSON command counts, backend feature flags, resource creation counts, target dimensions, backend
|
||||
name, trace marker/scope and draw summary, labeled descriptor counts,
|
||||
render-pass/depth-clear counts, and draw
|
||||
descriptor vertex/index totals, scissor/depth/blend-state plus
|
||||
|
||||
@@ -654,6 +654,16 @@ const char* RecordingRenderDevice::backend_name() const noexcept
|
||||
return "recording";
|
||||
}
|
||||
|
||||
RenderDeviceFeatures RecordingRenderDevice::features() const noexcept
|
||||
{
|
||||
return RenderDeviceFeatures {
|
||||
.explicit_texture_transitions = true,
|
||||
.texture_copy = true,
|
||||
.render_target_blit = true,
|
||||
.frame_capture = true,
|
||||
};
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::unique_ptr<ITexture2D>> RecordingRenderDevice::create_texture(
|
||||
TextureDesc desc) noexcept
|
||||
{
|
||||
|
||||
@@ -199,6 +199,7 @@ public:
|
||||
RecordingRenderDevice() noexcept;
|
||||
|
||||
[[nodiscard]] const char* backend_name() const noexcept override;
|
||||
[[nodiscard]] RenderDeviceFeatures features() const noexcept override;
|
||||
[[nodiscard]] pp::foundation::Result<std::unique_ptr<ITexture2D>> create_texture(
|
||||
TextureDesc desc) noexcept override;
|
||||
[[nodiscard]] pp::foundation::Result<std::unique_ptr<IRenderTarget>> create_render_target(
|
||||
|
||||
@@ -226,6 +226,16 @@ struct ShaderProgramDesc {
|
||||
ShaderStageSource fragment;
|
||||
};
|
||||
|
||||
struct RenderDeviceFeatures {
|
||||
bool framebuffer_fetch = false;
|
||||
bool explicit_texture_transitions = false;
|
||||
bool texture_copy = false;
|
||||
bool render_target_blit = false;
|
||||
bool frame_capture = false;
|
||||
bool float16_render_targets = false;
|
||||
bool float32_render_targets = false;
|
||||
};
|
||||
|
||||
class ITexture2D {
|
||||
public:
|
||||
virtual ~ITexture2D() = default;
|
||||
@@ -321,6 +331,7 @@ class IRenderDevice {
|
||||
public:
|
||||
virtual ~IRenderDevice() = default;
|
||||
[[nodiscard]] virtual const char* backend_name() const noexcept = 0;
|
||||
[[nodiscard]] virtual RenderDeviceFeatures features() const noexcept = 0;
|
||||
[[nodiscard]] virtual pp::foundation::Result<std::unique_ptr<ITexture2D>> create_texture(
|
||||
TextureDesc desc) noexcept = 0;
|
||||
[[nodiscard]] virtual pp::foundation::Result<std::unique_ptr<IRenderTarget>> create_render_target(
|
||||
|
||||
@@ -176,6 +176,18 @@ OpenGlCapabilities detect_opengl_capabilities(
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
pp::renderer::RenderDeviceFeatures render_device_features(OpenGlCapabilities capabilities) noexcept
|
||||
{
|
||||
return pp::renderer::RenderDeviceFeatures {
|
||||
.framebuffer_fetch = capabilities.framebuffer_fetch,
|
||||
.texture_copy = true,
|
||||
.render_target_blit = true,
|
||||
.frame_capture = true,
|
||||
.float16_render_targets = capabilities.float16_textures,
|
||||
.float32_render_targets = capabilities.float32_textures,
|
||||
};
|
||||
}
|
||||
|
||||
std::uint32_t extension_count_query() noexcept
|
||||
{
|
||||
return gl_num_extensions;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "renderer_api/renderer_api.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
@@ -46,6 +48,8 @@ struct OpenGlWindowsWglContextConfig {
|
||||
[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
|
||||
std::span<const std::string_view> extensions,
|
||||
OpenGlRuntime runtime) noexcept;
|
||||
[[nodiscard]] pp::renderer::RenderDeviceFeatures render_device_features(
|
||||
OpenGlCapabilities capabilities) noexcept;
|
||||
|
||||
[[nodiscard]] std::uint32_t extension_count_query() noexcept;
|
||||
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
|
||||
|
||||
@@ -365,7 +365,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\".*\"width\":32.*\"height\":16.*\"createdResources\":7.*\"labeledCommandDescriptors\":16.*\"commands\":25.*\"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.*\"labeledCommandDescriptors\":16.*\"commands\":25.*\"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_rejects_oversized_target
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
|
||||
@@ -43,6 +43,7 @@ using pp::renderer::RecordingRenderDevice;
|
||||
using pp::renderer::RecordingRenderTarget;
|
||||
using pp::renderer::RecordingShaderProgram;
|
||||
using pp::renderer::RecordingTexture2D;
|
||||
using pp::renderer::RenderDeviceFeatures;
|
||||
using pp::renderer::RenderPassDesc;
|
||||
using pp::renderer::SamplerAddressMode;
|
||||
using pp::renderer::sampler_address_mode_name;
|
||||
@@ -596,6 +597,19 @@ public:
|
||||
return "fake";
|
||||
}
|
||||
|
||||
[[nodiscard]] RenderDeviceFeatures features() const noexcept override
|
||||
{
|
||||
return RenderDeviceFeatures {
|
||||
.framebuffer_fetch = true,
|
||||
.explicit_texture_transitions = true,
|
||||
.texture_copy = true,
|
||||
.render_target_blit = true,
|
||||
.frame_capture = true,
|
||||
.float16_render_targets = true,
|
||||
.float32_render_targets = true,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<std::unique_ptr<pp::renderer::ITexture2D>> create_texture(
|
||||
TextureDesc desc) noexcept override
|
||||
{
|
||||
@@ -1552,6 +1566,14 @@ void renderer_interfaces_support_backend_neutral_dispatch(pp::tests::Harness& h)
|
||||
FakeMesh mesh;
|
||||
|
||||
PP_EXPECT(h, device.backend_name() == std::string_view("fake"));
|
||||
const auto features = device.features();
|
||||
PP_EXPECT(h, features.framebuffer_fetch);
|
||||
PP_EXPECT(h, features.explicit_texture_transitions);
|
||||
PP_EXPECT(h, features.texture_copy);
|
||||
PP_EXPECT(h, features.render_target_blit);
|
||||
PP_EXPECT(h, features.frame_capture);
|
||||
PP_EXPECT(h, features.float16_render_targets);
|
||||
PP_EXPECT(h, features.float32_render_targets);
|
||||
PP_EXPECT(h, device.trace()->begin_scope("renderer", "dispatch").ok());
|
||||
PP_EXPECT(h, device.trace()->marker("renderer", "begin").ok());
|
||||
PP_EXPECT(h, device.trace()->end_scope().ok());
|
||||
@@ -1690,7 +1712,15 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
||||
.debug_name = "factory-mesh",
|
||||
});
|
||||
const auto readback = device.create_readback_buffer(8U * 4U * 4U);
|
||||
const auto features = device.features();
|
||||
|
||||
PP_EXPECT(h, !features.framebuffer_fetch);
|
||||
PP_EXPECT(h, features.explicit_texture_transitions);
|
||||
PP_EXPECT(h, features.texture_copy);
|
||||
PP_EXPECT(h, features.render_target_blit);
|
||||
PP_EXPECT(h, features.frame_capture);
|
||||
PP_EXPECT(h, !features.float16_render_targets);
|
||||
PP_EXPECT(h, !features.float32_render_targets);
|
||||
PP_EXPECT(h, texture.ok());
|
||||
PP_EXPECT(h, texture.value()->desc().extent.width == 8U);
|
||||
PP_EXPECT(h, !has_texture_usage(texture.value()->desc().usage, TextureUsage::render_target));
|
||||
|
||||
@@ -36,6 +36,15 @@ void detects_common_extension_capabilities(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, capabilities.map_buffer_alignment);
|
||||
PP_EXPECT(h, !capabilities.float32_textures);
|
||||
PP_EXPECT(h, !capabilities.float16_textures);
|
||||
|
||||
const auto features = pp::renderer::gl::render_device_features(capabilities);
|
||||
PP_EXPECT(h, features.framebuffer_fetch);
|
||||
PP_EXPECT(h, !features.explicit_texture_transitions);
|
||||
PP_EXPECT(h, features.texture_copy);
|
||||
PP_EXPECT(h, features.render_target_blit);
|
||||
PP_EXPECT(h, features.frame_capture);
|
||||
PP_EXPECT(h, !features.float16_render_targets);
|
||||
PP_EXPECT(h, !features.float32_render_targets);
|
||||
}
|
||||
|
||||
void treats_desktop_gl_float_rendering_as_core(pp::tests::Harness& h)
|
||||
@@ -47,6 +56,10 @@ void treats_desktop_gl_float_rendering_as_core(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, capabilities.float32_textures);
|
||||
PP_EXPECT(h, capabilities.float32_linear);
|
||||
PP_EXPECT(h, capabilities.float16_textures);
|
||||
|
||||
const auto features = pp::renderer::gl::render_device_features(capabilities);
|
||||
PP_EXPECT(h, features.float16_render_targets);
|
||||
PP_EXPECT(h, features.float32_render_targets);
|
||||
}
|
||||
|
||||
void detects_gles_texture_float_extensions(pp::tests::Harness& h)
|
||||
|
||||
@@ -203,6 +203,11 @@ std::string json_escape(std::string_view value)
|
||||
return escaped;
|
||||
}
|
||||
|
||||
const char* json_bool(bool value) noexcept
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
pp::foundation::Result<float> parse_float_arg(std::string_view text)
|
||||
{
|
||||
float value = 0.0F;
|
||||
@@ -2566,6 +2571,7 @@ int record_render(int argc, char** argv)
|
||||
}
|
||||
};
|
||||
const auto commands = device.commands();
|
||||
const auto features = device.features();
|
||||
for (const auto& command : commands) {
|
||||
if (command.kind == pp::renderer::RecordedRenderCommandKind::begin_render_pass) {
|
||||
++render_passes;
|
||||
@@ -2650,6 +2656,14 @@ int record_render(int argc, char** argv)
|
||||
|
||||
std::cout << "{\"ok\":true,\"command\":\"record-render\""
|
||||
<< ",\"backend\":\"" << device.backend_name() << "\""
|
||||
<< ",\"features\":{\"framebufferFetch\":" << json_bool(features.framebuffer_fetch)
|
||||
<< ",\"explicitTextureTransitions\":" << json_bool(features.explicit_texture_transitions)
|
||||
<< ",\"textureCopy\":" << json_bool(features.texture_copy)
|
||||
<< ",\"renderTargetBlit\":" << json_bool(features.render_target_blit)
|
||||
<< ",\"frameCapture\":" << json_bool(features.frame_capture)
|
||||
<< ",\"float16RenderTargets\":" << json_bool(features.float16_render_targets)
|
||||
<< ",\"float32RenderTargets\":" << json_bool(features.float32_render_targets)
|
||||
<< "}"
|
||||
<< ",\"target\":{\"width\":" << args.width
|
||||
<< ",\"height\":" << args.height
|
||||
<< ",\"format\":\"rgba8\"}"
|
||||
|
||||
Reference in New Issue
Block a user