Add renderer texture usage contract
This commit is contained in:
@@ -285,12 +285,12 @@ Known local toolchain state:
|
||||
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, 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,
|
||||
shader-uniform writes, explicit draw descriptor ranges, texture-copy regions,
|
||||
readback bounds, frame-capture sources, destination buffer sizes, and
|
||||
render-target blit regions, records
|
||||
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, shader-uniform writes, explicit draw descriptor ranges,
|
||||
texture-copy regions, readback bounds, frame-capture sources, destination
|
||||
buffer sizes, and render-target blit regions, records
|
||||
render-pass-clear/scissor/depth/blend/shader-uniform/texture-bind/
|
||||
sampler-bind/draw/upload/texture-copy/readback/frame-capture/blit commands,
|
||||
draw mesh inputs, explicit draw ranges, and records trace markers without a
|
||||
|
||||
@@ -414,14 +414,15 @@ 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 texture descriptor, byte-size, viewport, mesh, readback bounds, command
|
||||
context, render device, shader program descriptor, mesh, render target,
|
||||
readback byte-size helpers, texture-upload/readback command validation,
|
||||
frame-capture byte-size helpers, frame-capture command validation,
|
||||
render-target blit validation, texture-slot binding validation, blend-state
|
||||
validation, scissor-state validation, depth-state validation, trace interface
|
||||
validation, sampler-state validation, and the canonical PanoPainter shader
|
||||
catalog now consumed by the legacy OpenGL app initialization path.
|
||||
with 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-upload/readback command validation, frame-capture byte-size helpers,
|
||||
frame-capture command validation, render-target blit validation, texture-slot
|
||||
binding validation, blend-state validation, scissor-state validation,
|
||||
depth-state validation, trace interface validation, sampler-state validation,
|
||||
and the canonical PanoPainter shader catalog now consumed by the legacy
|
||||
OpenGL app initialization path.
|
||||
`pp_renderer_gl` now exists as the first OpenGL backend library and owns pure
|
||||
OpenGL capability detection for framebuffer fetch, map-buffer alignment, and
|
||||
float texture support. It also owns the OpenGL texture upload-type mapping used
|
||||
@@ -720,13 +721,14 @@ Results:
|
||||
per-layer frame duration, and PNG-encoded face-payload export to PPI bytes,
|
||||
plus malformed payload rejection at the export boundary.
|
||||
- `pp_renderer_api_tests` passed, including shader descriptor validation,
|
||||
PanoPainter shader catalog validation, readback byte-size and command-order
|
||||
validation, texture-upload byte-count validation, frame-capture byte-size and
|
||||
command-order validation, render-target blit validation, texture-slot binding
|
||||
validation, blend-state validation, scissor-state validation,
|
||||
render-pass color/depth/stencil clear validation, shader-uniform write
|
||||
validation, draw descriptor/range validation, backend-neutral resource
|
||||
factory validation, texture-copy validation, recording
|
||||
PanoPainter shader catalog validation, explicit texture usage validation,
|
||||
readback byte-size and command-order validation, texture-upload byte-count
|
||||
validation, frame-capture byte-size and command-order validation,
|
||||
render-target blit validation, texture-slot binding validation, blend-state
|
||||
validation, scissor-state validation, render-pass color/depth/stencil clear
|
||||
validation, shader-uniform write validation, draw descriptor/range
|
||||
validation, backend-neutral resource factory validation, texture-copy
|
||||
validation, recording
|
||||
render-pass clear/scissor/depth/blend/shader-uniform/texture/sampler-bind/
|
||||
upload/texture-copy/readback/frame-capture/blit command capture, draw
|
||||
mesh-input capture, explicit draw-range capture, and invalid catalog
|
||||
@@ -826,10 +828,11 @@ Results:
|
||||
- `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict
|
||||
renderer-owned resource factory and
|
||||
command-order/render-pass-clear/scissor-state/depth-state/blend-state/
|
||||
texture-bind/sampler-bind/shader-uniform/texture-upload/readback/
|
||||
frame-capture/blit validation plus explicit draw descriptor and texture-copy
|
||||
validation; it creates validated textures, render targets, shaders, meshes,
|
||||
and readback buffers, then records commands, trace markers, render-pass
|
||||
texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/
|
||||
readback/frame-capture/blit validation plus explicit draw descriptor and
|
||||
texture-copy validation; it creates validated textures, render targets,
|
||||
shaders, meshes, and readback buffers, then records commands, trace markers,
|
||||
render-pass
|
||||
color/depth/stencil clear intent, scissor state, depth state, blend state,
|
||||
shader uniform writes, texture/sampler binds, draw mesh inputs, explicit draw
|
||||
ranges, texture uploads/copies/readbacks, frame captures, and render-target
|
||||
|
||||
@@ -101,8 +101,8 @@ pp::foundation::Status RecordingCommandContext::begin_render_pass(
|
||||
}
|
||||
|
||||
active_target_ = target.color_desc();
|
||||
if (!active_target_.render_target) {
|
||||
return pp::foundation::Status::invalid_argument("render target texture must be flagged as render_target");
|
||||
if (!has_texture_usage(active_target_.usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Status::invalid_argument("render target texture must allow render_target usage");
|
||||
}
|
||||
|
||||
const auto size_status = texture_byte_size(active_target_);
|
||||
@@ -256,6 +256,10 @@ pp::foundation::Status RecordingCommandContext::bind_texture(
|
||||
}
|
||||
|
||||
const auto desc = texture.desc();
|
||||
if (!has_texture_usage(desc.usage, TextureUsage::sampled)) {
|
||||
return pp::foundation::Status::invalid_argument("bound texture must allow sampled usage");
|
||||
}
|
||||
|
||||
const auto size_status = texture_byte_size(desc);
|
||||
if (!size_status.ok()) {
|
||||
return size_status.status();
|
||||
@@ -351,6 +355,10 @@ pp::foundation::Status RecordingCommandContext::read_texture(
|
||||
}
|
||||
|
||||
const auto desc = texture.desc();
|
||||
if (!has_texture_usage(desc.usage, TextureUsage::readback_source)) {
|
||||
return pp::foundation::Status::invalid_argument("readback texture must allow readback_source usage");
|
||||
}
|
||||
|
||||
const auto bytes = readback_byte_size(desc, region);
|
||||
if (!bytes) {
|
||||
return bytes.status();
|
||||
@@ -379,6 +387,10 @@ pp::foundation::Status RecordingCommandContext::upload_texture(
|
||||
}
|
||||
|
||||
const auto desc = texture.desc();
|
||||
if (!has_texture_usage(desc.usage, TextureUsage::upload_destination)) {
|
||||
return pp::foundation::Status::invalid_argument("texture upload destination must allow upload_destination usage");
|
||||
}
|
||||
|
||||
const auto bytes = readback_byte_size(desc, region);
|
||||
if (!bytes) {
|
||||
return bytes.status();
|
||||
@@ -560,6 +572,11 @@ const char* RecordingRenderDevice::backend_name() const noexcept
|
||||
pp::foundation::Result<std::unique_ptr<ITexture2D>> RecordingRenderDevice::create_texture(
|
||||
TextureDesc desc) noexcept
|
||||
{
|
||||
const auto desc_status = validate_texture_desc(desc);
|
||||
if (!desc_status.ok()) {
|
||||
return pp::foundation::Result<std::unique_ptr<ITexture2D>>::failure(desc_status);
|
||||
}
|
||||
|
||||
const auto bytes = texture_byte_size(desc);
|
||||
if (!bytes.ok()) {
|
||||
return pp::foundation::Result<std::unique_ptr<ITexture2D>>::failure(bytes.status());
|
||||
@@ -571,9 +588,14 @@ pp::foundation::Result<std::unique_ptr<ITexture2D>> RecordingRenderDevice::creat
|
||||
pp::foundation::Result<std::unique_ptr<IRenderTarget>> RecordingRenderDevice::create_render_target(
|
||||
TextureDesc color_desc) noexcept
|
||||
{
|
||||
if (!color_desc.render_target) {
|
||||
if (!has_texture_usage(color_desc.usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Result<std::unique_ptr<IRenderTarget>>::failure(
|
||||
pp::foundation::Status::invalid_argument("render target texture must be flagged as render_target"));
|
||||
pp::foundation::Status::invalid_argument("render target texture must allow render_target usage"));
|
||||
}
|
||||
|
||||
const auto desc_status = validate_texture_desc(color_desc);
|
||||
if (!desc_status.ok()) {
|
||||
return pp::foundation::Result<std::unique_ptr<IRenderTarget>>::failure(desc_status);
|
||||
}
|
||||
|
||||
const auto bytes = texture_byte_size(color_desc);
|
||||
|
||||
@@ -47,6 +47,13 @@ std::uint32_t bytes_per_pixel(TextureFormat format) noexcept
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool has_texture_usage(TextureUsage usage, TextureUsage required) noexcept
|
||||
{
|
||||
const auto usage_bits = static_cast<std::uint32_t>(usage);
|
||||
const auto required_bits = static_cast<std::uint32_t>(required);
|
||||
return required_bits != 0U && (usage_bits & required_bits) == required_bits;
|
||||
}
|
||||
|
||||
pp::foundation::Status validate_extent(Extent2D extent) noexcept
|
||||
{
|
||||
if (extent.width == 0 || extent.height == 0) {
|
||||
@@ -60,19 +67,50 @@ pp::foundation::Status validate_extent(Extent2D extent) noexcept
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::uint64_t> texture_byte_size(TextureDesc desc) noexcept
|
||||
pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept
|
||||
{
|
||||
constexpr auto allowed_usage = TextureUsage::sampled
|
||||
| TextureUsage::render_target
|
||||
| TextureUsage::upload_destination
|
||||
| TextureUsage::readback_source
|
||||
| TextureUsage::copy_source
|
||||
| TextureUsage::copy_destination;
|
||||
|
||||
const auto usage_bits = static_cast<std::uint32_t>(usage);
|
||||
const auto allowed_bits = static_cast<std::uint32_t>(allowed_usage);
|
||||
if (usage_bits == 0U) {
|
||||
return pp::foundation::Status::invalid_argument("texture usage must not be empty");
|
||||
}
|
||||
|
||||
if ((usage_bits & ~allowed_bits) != 0U) {
|
||||
return pp::foundation::Status::invalid_argument("texture usage contains unsupported flags");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept
|
||||
{
|
||||
const auto extent_status = validate_extent(desc.extent);
|
||||
if (!extent_status.ok()) {
|
||||
return pp::foundation::Result<std::uint64_t>::failure(extent_status);
|
||||
return extent_status;
|
||||
}
|
||||
|
||||
if (bytes_per_pixel(desc.format) == 0U) {
|
||||
return pp::foundation::Status::invalid_argument("texture format is not supported");
|
||||
}
|
||||
|
||||
return validate_texture_usage(desc.usage);
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::uint64_t> texture_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);
|
||||
}
|
||||
|
||||
const auto bpp = static_cast<std::uint64_t>(bytes_per_pixel(desc.format));
|
||||
if (bpp == 0) {
|
||||
return pp::foundation::Result<std::uint64_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("texture format is not supported"));
|
||||
}
|
||||
|
||||
const auto width = static_cast<std::uint64_t>(desc.extent.width);
|
||||
const auto height = static_cast<std::uint64_t>(desc.extent.height);
|
||||
if (width > std::numeric_limits<std::uint64_t>::max() / height) {
|
||||
@@ -481,11 +519,16 @@ 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
|
||||
{
|
||||
if (!desc.render_target) {
|
||||
if (!has_texture_usage(desc.usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Result<std::uint64_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("frame capture source must be a render target"));
|
||||
}
|
||||
|
||||
if (!has_texture_usage(desc.usage, TextureUsage::readback_source)) {
|
||||
return pp::foundation::Result<std::uint64_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("frame capture source must allow readback"));
|
||||
}
|
||||
|
||||
return texture_byte_size(desc);
|
||||
}
|
||||
|
||||
@@ -495,6 +538,14 @@ pp::foundation::Status validate_texture_copy_descs(
|
||||
TextureDesc destination,
|
||||
ReadbackRegion destination_region) noexcept
|
||||
{
|
||||
if (!has_texture_usage(source.usage, TextureUsage::copy_source)) {
|
||||
return pp::foundation::Status::invalid_argument("texture copy source must allow copy_source usage");
|
||||
}
|
||||
|
||||
if (!has_texture_usage(destination.usage, TextureUsage::copy_destination)) {
|
||||
return pp::foundation::Status::invalid_argument("texture copy destination must allow copy_destination usage");
|
||||
}
|
||||
|
||||
if (source.format != destination.format) {
|
||||
return pp::foundation::Status::invalid_argument("texture copy endpoints must use matching formats");
|
||||
}
|
||||
@@ -524,10 +575,19 @@ pp::foundation::Status validate_blit_filter(BlitFilter filter) noexcept
|
||||
|
||||
pp::foundation::Status validate_blit_descs(TextureDesc source, TextureDesc destination) noexcept
|
||||
{
|
||||
if (!source.render_target || !destination.render_target) {
|
||||
if (!has_texture_usage(source.usage, TextureUsage::render_target)
|
||||
|| !has_texture_usage(destination.usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Status::invalid_argument("blit endpoints must be render targets");
|
||||
}
|
||||
|
||||
if (!has_texture_usage(source.usage, TextureUsage::copy_source)) {
|
||||
return pp::foundation::Status::invalid_argument("blit source must allow copy_source usage");
|
||||
}
|
||||
|
||||
if (!has_texture_usage(destination.usage, TextureUsage::copy_destination)) {
|
||||
return pp::foundation::Status::invalid_argument("blit destination must allow copy_destination usage");
|
||||
}
|
||||
|
||||
if (source.format != destination.format) {
|
||||
return pp::foundation::Status::invalid_argument("blit endpoints must use matching texture formats");
|
||||
}
|
||||
|
||||
@@ -22,6 +22,34 @@ enum class TextureFormat : std::uint8_t {
|
||||
depth24_stencil8,
|
||||
};
|
||||
|
||||
enum class TextureUsage : std::uint32_t {
|
||||
none = 0,
|
||||
sampled = 1U << 0U,
|
||||
render_target = 1U << 1U,
|
||||
upload_destination = 1U << 2U,
|
||||
readback_source = 1U << 3U,
|
||||
copy_source = 1U << 4U,
|
||||
copy_destination = 1U << 5U,
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr TextureUsage operator|(TextureUsage lhs, TextureUsage rhs) noexcept
|
||||
{
|
||||
return static_cast<TextureUsage>(
|
||||
static_cast<std::uint32_t>(lhs) | static_cast<std::uint32_t>(rhs));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr TextureUsage operator&(TextureUsage lhs, TextureUsage rhs) noexcept
|
||||
{
|
||||
return static_cast<TextureUsage>(
|
||||
static_cast<std::uint32_t>(lhs) & static_cast<std::uint32_t>(rhs));
|
||||
}
|
||||
|
||||
constexpr TextureUsage& operator|=(TextureUsage& lhs, TextureUsage rhs) noexcept
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
struct Extent2D {
|
||||
std::uint32_t width = 0;
|
||||
std::uint32_t height = 0;
|
||||
@@ -30,7 +58,11 @@ struct Extent2D {
|
||||
struct TextureDesc {
|
||||
Extent2D extent;
|
||||
TextureFormat format = TextureFormat::rgba8;
|
||||
bool render_target = false;
|
||||
TextureUsage usage = TextureUsage::sampled
|
||||
| TextureUsage::upload_destination
|
||||
| TextureUsage::readback_source
|
||||
| TextureUsage::copy_source
|
||||
| TextureUsage::copy_destination;
|
||||
};
|
||||
|
||||
struct ReadbackRegion {
|
||||
@@ -279,7 +311,10 @@ public:
|
||||
};
|
||||
|
||||
[[nodiscard]] std::uint32_t bytes_per_pixel(TextureFormat format) noexcept;
|
||||
[[nodiscard]] bool has_texture_usage(TextureUsage usage, TextureUsage required) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_extent(Extent2D extent) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_texture_usage(TextureUsage usage) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_texture_desc(TextureDesc desc) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_viewport(Viewport viewport, Extent2D target_extent) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_scissor(ScissorRect scissor, Extent2D target_extent) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status validate_render_pass_desc(RenderPassDesc desc) noexcept;
|
||||
|
||||
@@ -26,6 +26,7 @@ using pp::renderer::DepthState;
|
||||
using pp::renderer::DrawDesc;
|
||||
using pp::renderer::Extent2D;
|
||||
using pp::renderer::frame_capture_byte_size;
|
||||
using pp::renderer::has_texture_usage;
|
||||
using pp::renderer::ICommandContext;
|
||||
using pp::renderer::IMesh;
|
||||
using pp::renderer::IRenderDevice;
|
||||
@@ -53,6 +54,7 @@ using pp::renderer::ShaderProgramDesc;
|
||||
using pp::renderer::ShaderStageSource;
|
||||
using pp::renderer::TextureDesc;
|
||||
using pp::renderer::TextureFormat;
|
||||
using pp::renderer::TextureUsage;
|
||||
using pp::renderer::Viewport;
|
||||
using pp::renderer::max_shader_source_bytes;
|
||||
using pp::renderer::max_shader_uniform_bytes;
|
||||
@@ -85,7 +87,9 @@ using pp::renderer::validate_shader_catalog;
|
||||
using pp::renderer::validate_shader_program_desc;
|
||||
using pp::renderer::validate_shader_uniform_write;
|
||||
using pp::renderer::validate_texture_copy_descs;
|
||||
using pp::renderer::validate_texture_desc;
|
||||
using pp::renderer::validate_texture_slot;
|
||||
using pp::renderer::validate_texture_usage;
|
||||
using pp::renderer::validate_viewport;
|
||||
|
||||
namespace {
|
||||
@@ -95,7 +99,7 @@ public:
|
||||
explicit FakeRenderTarget(TextureDesc desc = TextureDesc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
}) noexcept
|
||||
: desc_(desc)
|
||||
{
|
||||
@@ -151,7 +155,7 @@ public:
|
||||
explicit FakeTexture(TextureDesc desc = TextureDesc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
}) noexcept
|
||||
: desc_(desc)
|
||||
{
|
||||
@@ -204,6 +208,9 @@ public:
|
||||
if (!render_pass_status.ok()) {
|
||||
return render_pass_status;
|
||||
}
|
||||
if (!has_texture_usage(target.color_desc().usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Status::invalid_argument("render target texture must allow render_target usage");
|
||||
}
|
||||
in_render_pass = true;
|
||||
last_render_pass_desc = desc;
|
||||
return validate_extent(target.color_desc().extent);
|
||||
@@ -291,6 +298,9 @@ public:
|
||||
if (!slot_status.ok()) {
|
||||
return slot_status;
|
||||
}
|
||||
if (!has_texture_usage(texture.desc().usage, TextureUsage::sampled)) {
|
||||
return pp::foundation::Status::invalid_argument("bound texture must allow sampled usage");
|
||||
}
|
||||
const auto bytes = texture_byte_size(texture.desc());
|
||||
if (!bytes) {
|
||||
return bytes.status();
|
||||
@@ -354,6 +364,9 @@ public:
|
||||
ReadbackRegion region,
|
||||
pp::renderer::IReadbackBuffer& destination) noexcept override
|
||||
{
|
||||
if (!has_texture_usage(texture.desc().usage, TextureUsage::readback_source)) {
|
||||
return pp::foundation::Status::invalid_argument("readback texture must allow readback_source usage");
|
||||
}
|
||||
const auto bytes = readback_byte_size(texture.desc(), region);
|
||||
if (!bytes) {
|
||||
return bytes.status();
|
||||
@@ -370,6 +383,9 @@ public:
|
||||
ReadbackRegion region,
|
||||
std::span<const std::byte> rgba_or_channel_bytes) noexcept override
|
||||
{
|
||||
if (!has_texture_usage(texture.desc().usage, TextureUsage::upload_destination)) {
|
||||
return pp::foundation::Status::invalid_argument("texture upload destination must allow upload_destination usage");
|
||||
}
|
||||
const auto bytes = readback_byte_size(texture.desc(), region);
|
||||
if (!bytes) {
|
||||
return bytes.status();
|
||||
@@ -511,9 +527,9 @@ public:
|
||||
[[nodiscard]] pp::foundation::Result<std::unique_ptr<IRenderTarget>> create_render_target(
|
||||
TextureDesc color_desc) noexcept override
|
||||
{
|
||||
if (!color_desc.render_target) {
|
||||
if (!has_texture_usage(color_desc.usage, TextureUsage::render_target)) {
|
||||
return pp::foundation::Result<std::unique_ptr<IRenderTarget>>::failure(
|
||||
pp::foundation::Status::invalid_argument("render target texture must be flagged as render_target"));
|
||||
pp::foundation::Status::invalid_argument("render target texture must allow render_target usage"));
|
||||
}
|
||||
|
||||
const auto bytes = texture_byte_size(color_desc);
|
||||
@@ -590,6 +606,13 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
constexpr TextureUsage all_texture_usages = TextureUsage::sampled
|
||||
| TextureUsage::render_target
|
||||
| TextureUsage::upload_destination
|
||||
| TextureUsage::readback_source
|
||||
| TextureUsage::copy_source
|
||||
| TextureUsage::copy_destination;
|
||||
|
||||
void computes_texture_sizes(pp::tests::Harness& h)
|
||||
{
|
||||
const auto rgba = texture_byte_size(TextureDesc {
|
||||
@@ -608,6 +631,51 @@ void computes_texture_sizes(pp::tests::Harness& h)
|
||||
PP_EXPECT(h, texture_format_name(TextureFormat::depth24_stencil8) == std::string_view("depth24_stencil8"));
|
||||
}
|
||||
|
||||
void validates_texture_usage_contract(pp::tests::Harness& h)
|
||||
{
|
||||
const TextureDesc sampled_desc {
|
||||
.extent = Extent2D { .width = 4, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::sampled,
|
||||
};
|
||||
const TextureDesc all_usage_desc {
|
||||
.extent = Extent2D { .width = 4, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = all_texture_usages,
|
||||
};
|
||||
const TextureDesc empty_usage_desc {
|
||||
.extent = Extent2D { .width = 4, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::none,
|
||||
};
|
||||
const TextureDesc unknown_usage_desc {
|
||||
.extent = Extent2D { .width = 4, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = static_cast<TextureUsage>(1U << 31U),
|
||||
};
|
||||
const TextureDesc unknown_format_desc {
|
||||
.extent = Extent2D { .width = 4, .height = 4 },
|
||||
.format = static_cast<TextureFormat>(255),
|
||||
};
|
||||
|
||||
PP_EXPECT(h, has_texture_usage(all_texture_usages, TextureUsage::render_target));
|
||||
PP_EXPECT(h, !has_texture_usage(TextureUsage::sampled, TextureUsage::render_target));
|
||||
PP_EXPECT(h, validate_texture_usage(TextureUsage::sampled | TextureUsage::copy_source).ok());
|
||||
PP_EXPECT(h, validate_texture_desc(sampled_desc).ok());
|
||||
PP_EXPECT(h, validate_texture_desc(all_usage_desc).ok());
|
||||
|
||||
const auto empty_usage = validate_texture_desc(empty_usage_desc);
|
||||
const auto unknown_usage = validate_texture_desc(unknown_usage_desc);
|
||||
const auto unknown_format = validate_texture_desc(unknown_format_desc);
|
||||
|
||||
PP_EXPECT(h, !empty_usage.ok());
|
||||
PP_EXPECT(h, empty_usage.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !unknown_usage.ok());
|
||||
PP_EXPECT(h, unknown_usage.code == StatusCode::invalid_argument);
|
||||
PP_EXPECT(h, !unknown_format.ok());
|
||||
PP_EXPECT(h, unknown_format.code == StatusCode::invalid_argument);
|
||||
}
|
||||
|
||||
void rejects_invalid_or_excessive_extents(pp::tests::Harness& h)
|
||||
{
|
||||
const auto zero = validate_extent(Extent2D { .width = 0, .height = 1 });
|
||||
@@ -630,7 +698,7 @@ void validates_readback_bounds(pp::tests::Harness& h)
|
||||
const TextureDesc desc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
|
||||
PP_EXPECT(h, validate_readback_region(desc, ReadbackRegion { .x = 0, .y = 0, .width = 64, .height = 32 }).ok());
|
||||
@@ -653,12 +721,12 @@ void computes_readback_byte_sizes(pp::tests::Harness& h)
|
||||
const TextureDesc rgba_desc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
const TextureDesc r8_desc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::r8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
|
||||
const auto rgba = readback_byte_size(rgba_desc, ReadbackRegion { .x = 4, .y = 2, .width = 8, .height = 3 });
|
||||
@@ -678,12 +746,12 @@ void computes_frame_capture_byte_sizes(pp::tests::Harness& h)
|
||||
const TextureDesc target_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
const TextureDesc texture_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = false,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
|
||||
const auto capture = frame_capture_byte_size(target_desc);
|
||||
@@ -700,17 +768,17 @@ void validates_blit_contract(pp::tests::Harness& h)
|
||||
const TextureDesc target_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
const TextureDesc r8_target_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::r8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
const TextureDesc texture_desc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = false,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
};
|
||||
|
||||
PP_EXPECT(h, validate_blit_descs(target_desc, target_desc).ok());
|
||||
@@ -1239,12 +1307,12 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
||||
const auto texture = device.create_texture(TextureDesc {
|
||||
.extent = Extent2D { .width = 8, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = false,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
const auto target = device.create_render_target(TextureDesc {
|
||||
.extent = Extent2D { .width = 8, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
const auto shader = device.create_shader_program(ShaderProgramDesc {
|
||||
.debug_name = "factory-shader",
|
||||
@@ -1260,9 +1328,9 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
||||
|
||||
PP_EXPECT(h, texture.ok());
|
||||
PP_EXPECT(h, texture.value()->desc().extent.width == 8U);
|
||||
PP_EXPECT(h, !texture.value()->desc().render_target);
|
||||
PP_EXPECT(h, !has_texture_usage(texture.value()->desc().usage, TextureUsage::render_target));
|
||||
PP_EXPECT(h, target.ok());
|
||||
PP_EXPECT(h, target.value()->color_desc().render_target);
|
||||
PP_EXPECT(h, has_texture_usage(target.value()->color_desc().usage, TextureUsage::render_target));
|
||||
PP_EXPECT(h, shader.ok());
|
||||
PP_EXPECT(h, shader.value()->debug_name() == std::string_view("factory-shader"));
|
||||
PP_EXPECT(h, mesh.ok());
|
||||
@@ -1277,7 +1345,7 @@ void render_devices_create_validated_resources(pp::tests::Harness& h)
|
||||
const auto bad_target = device.create_render_target(TextureDesc {
|
||||
.extent = Extent2D { .width = 8, .height = 4 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = false,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
const auto bad_shader = device.create_shader_program(ShaderProgramDesc {
|
||||
.debug_name = "bad-shader",
|
||||
@@ -1305,7 +1373,7 @@ void recording_renderer_records_shader_uniform_writes(pp::tests::Harness& h)
|
||||
RecordingRenderTarget target(TextureDesc {
|
||||
.extent = Extent2D { .width = 16, .height = 8 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingShaderProgram shader("uniform-shader");
|
||||
const std::array<std::byte, 64> uniform_bytes {};
|
||||
@@ -1348,19 +1416,19 @@ void recording_renderer_records_valid_command_sequences(pp::tests::Harness& h)
|
||||
RecordingTexture2D texture(TextureDesc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingReadbackBuffer readback_buffer(64U * 32U * 4U);
|
||||
const std::array<std::byte, 96> upload_bytes {};
|
||||
RecordingRenderTarget target(TextureDesc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingRenderTarget blit_target(TextureDesc {
|
||||
.extent = Extent2D { .width = 64, .height = 32 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingShaderProgram shader("recorded-shader");
|
||||
RecordingMesh mesh(MeshDesc { .vertex_count = 3, .index_count = 3, .topology = PrimitiveTopology::triangles });
|
||||
@@ -1540,22 +1608,57 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
RecordingRenderTarget target(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingRenderTarget non_render_target(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = false,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingRenderTarget r8_target(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::r8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = TextureUsage::render_target | TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture_without_sampled(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture_without_upload(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::sampled | TextureUsage::readback_source | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture_without_readback(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::copy_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture_without_copy_source(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_destination,
|
||||
});
|
||||
RecordingTexture2D texture_without_copy_destination(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::sampled | TextureUsage::upload_destination | TextureUsage::readback_source | TextureUsage::copy_source,
|
||||
});
|
||||
RecordingRenderTarget target_without_copy_source(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::render_target | TextureUsage::copy_destination | TextureUsage::readback_source,
|
||||
});
|
||||
RecordingRenderTarget target_without_copy_destination(TextureDesc {
|
||||
.extent = Extent2D { .width = 32, .height = 16 },
|
||||
.format = TextureFormat::rgba8,
|
||||
.usage = TextureUsage::render_target | TextureUsage::copy_source | TextureUsage::readback_source,
|
||||
});
|
||||
RecordingReadbackBuffer small_readback_buffer(3U);
|
||||
RecordingReadbackBuffer full_readback_buffer(32U * 16U * 4U);
|
||||
@@ -1692,6 +1795,11 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
const auto bind_texture_bad_slot = context.bind_texture(max_texture_slots, texture);
|
||||
PP_EXPECT(h, !bind_texture_bad_slot.ok());
|
||||
PP_EXPECT(h, bind_texture_bad_slot.code == StatusCode::out_of_range);
|
||||
|
||||
const auto bind_texture_without_sampled = context.bind_texture(0, texture_without_sampled);
|
||||
PP_EXPECT(h, !bind_texture_without_sampled.ok());
|
||||
PP_EXPECT(h, bind_texture_without_sampled.code == StatusCode::invalid_argument);
|
||||
|
||||
PP_EXPECT(h, context.bind_texture(0, texture).ok());
|
||||
|
||||
const auto bind_sampler_bad_slot = context.bind_sampler(max_texture_slots, SamplerDesc {});
|
||||
@@ -1759,6 +1867,13 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !upload_outside_bounds.ok());
|
||||
PP_EXPECT(h, upload_outside_bounds.code == StatusCode::out_of_range);
|
||||
|
||||
const auto upload_without_usage = context.upload_texture(
|
||||
texture_without_upload,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
one_pixel_upload);
|
||||
PP_EXPECT(h, !upload_without_usage.ok());
|
||||
PP_EXPECT(h, upload_without_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto copy_mismatched_regions = context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 2, .height = 1 },
|
||||
@@ -1775,6 +1890,22 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !copy_outside_bounds.ok());
|
||||
PP_EXPECT(h, copy_outside_bounds.code == StatusCode::out_of_range);
|
||||
|
||||
const auto copy_without_source_usage = context.copy_texture(
|
||||
texture_without_copy_source,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
PP_EXPECT(h, !copy_without_source_usage.ok());
|
||||
PP_EXPECT(h, copy_without_source_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto copy_without_destination_usage = context.copy_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
texture_without_copy_destination,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 });
|
||||
PP_EXPECT(h, !copy_without_destination_usage.ok());
|
||||
PP_EXPECT(h, copy_without_destination_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto upload_with_wrong_size = context.upload_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
@@ -1782,6 +1913,13 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !upload_with_wrong_size.ok());
|
||||
PP_EXPECT(h, upload_with_wrong_size.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto read_without_usage = context.read_texture(
|
||||
texture_without_readback,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
full_readback_buffer);
|
||||
PP_EXPECT(h, !read_without_usage.ok());
|
||||
PP_EXPECT(h, read_without_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto read_into_small_buffer = context.read_texture(
|
||||
texture,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
@@ -1815,6 +1953,24 @@ void recording_renderer_rejects_invalid_command_order_and_targets(pp::tests::Har
|
||||
PP_EXPECT(h, !blit_mismatched_format.ok());
|
||||
PP_EXPECT(h, blit_mismatched_format.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto blit_without_source_usage = context.blit_render_target(
|
||||
target_without_copy_source,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
target,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
BlitFilter::nearest);
|
||||
PP_EXPECT(h, !blit_without_source_usage.ok());
|
||||
PP_EXPECT(h, blit_without_source_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto blit_without_destination_usage = context.blit_render_target(
|
||||
target,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
target_without_copy_destination,
|
||||
ReadbackRegion { .x = 0, .y = 0, .width = 1, .height = 1 },
|
||||
BlitFilter::nearest);
|
||||
PP_EXPECT(h, !blit_without_destination_usage.ok());
|
||||
PP_EXPECT(h, blit_without_destination_usage.code == StatusCode::invalid_argument);
|
||||
|
||||
const auto blit_outside_bounds = context.blit_render_target(
|
||||
target,
|
||||
ReadbackRegion { .x = 31, .y = 15, .width = 2, .height = 1 },
|
||||
@@ -1840,6 +1996,7 @@ int main()
|
||||
{
|
||||
pp::tests::Harness harness;
|
||||
harness.run("computes_texture_sizes", computes_texture_sizes);
|
||||
harness.run("validates_texture_usage_contract", validates_texture_usage_contract);
|
||||
harness.run("rejects_invalid_or_excessive_extents", rejects_invalid_or_excessive_extents);
|
||||
harness.run("validates_readback_bounds", validates_readback_bounds);
|
||||
harness.run("computes_readback_byte_sizes", computes_readback_byte_sizes);
|
||||
|
||||
@@ -1642,7 +1642,7 @@ pp::foundation::Status parse_simulate_document_edits_args(
|
||||
const auto render_target_size = pp::renderer::texture_byte_size(pp::renderer::TextureDesc {
|
||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||
.format = pp::renderer::TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||
});
|
||||
if (!render_target_size) {
|
||||
return render_target_size.status();
|
||||
@@ -2214,17 +2214,17 @@ int record_render(int argc, char** argv)
|
||||
const auto texture = device.create_texture(pp::renderer::TextureDesc {
|
||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||
.format = pp::renderer::TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||
});
|
||||
const auto target = device.create_render_target(pp::renderer::TextureDesc {
|
||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||
.format = pp::renderer::TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||
});
|
||||
const auto blit_target = device.create_render_target(pp::renderer::TextureDesc {
|
||||
.extent = pp::renderer::Extent2D { .width = args.width, .height = args.height },
|
||||
.format = pp::renderer::TextureFormat::rgba8,
|
||||
.render_target = true,
|
||||
.usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::upload_destination | pp::renderer::TextureUsage::readback_source | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination,
|
||||
});
|
||||
const auto readback_buffer = device.create_readback_buffer(
|
||||
static_cast<std::uint64_t>(args.width) * args.height * 4U);
|
||||
|
||||
Reference in New Issue
Block a user