Route font mesh operations through renderer GL

This commit is contained in:
2026-06-03 07:29:09 +02:00
parent e1cce05bd6
commit 4de6f496ad
6 changed files with 279 additions and 77 deletions

View File

@@ -246,7 +246,9 @@ Known local toolchain state:
used before runtime capability detection are cataloged here. Legacy font used before runtime capability detection are cataloged here. Legacy font
atlas texture formats, text mesh buffer targets, attribute component and atlas texture formats, text mesh buffer targets, attribute component and
normalization tokens, draw primitive/index type, upload usage, and active normalization tokens, draw primitive/index type, upload usage, and active
texture unit selection also consume the backend mapping. Canvas undo/redo texture unit selection also consume the backend mapping. Text mesh
buffer/VAO creation, deferred index/vertex uploads, and indexed draw calls
now consume tested `pp_renderer_gl` mesh dispatch contracts too. Canvas undo/redo
dirty-region texture updates and readbacks also consume the backend-owned 2D dirty-region texture updates and readbacks also consume the backend-owned 2D
texture target, RGBA pixel format, and unsigned-byte component mapping. texture target, RGBA pixel format, and unsigned-byte component mapping.
`NodeViewport` preview rendering also consumes backend-owned viewport query, `NodeViewport` preview rendering also consumes backend-owned viewport query,

View File

@@ -693,7 +693,10 @@ mapping too. OpenGL extension enumeration query tokens used before runtime
capability detection also live in `pp_renderer_gl`. Legacy font atlas texture capability detection also live in `pp_renderer_gl`. Legacy font atlas texture
formats, text mesh buffer targets, attribute component/normalization, draw formats, text mesh buffer targets, attribute component/normalization, draw
primitive/index type, upload usage, and active texture unit selection also primitive/index type, upload usage, and active texture unit selection also
delegate to `pp_renderer_gl`; `Font` no longer spells GL enum names directly. delegate to `pp_renderer_gl`; text mesh buffer/VAO creation, deferred index
and vertex uploads, and indexed draw calls now execute through the same tested
mesh dispatch contracts used by `Shape`, leaving the retained `Font` utility
with thin GL adapter functions for mesh operations.
Canvas undo/redo dirty-region texture updates and readbacks now also delegate Canvas undo/redo dirty-region texture updates and readbacks now also delegate
their 2D texture target, RGBA pixel format, and unsigned-byte component type their 2D texture target, RGBA pixel format, and unsigned-byte component type
mapping to `pp_renderer_gl`. mapping to `pp_renderer_gl`.
@@ -1133,6 +1136,9 @@ Results:
dynamic buffer uploads, indexed and non-indexed draws, and resource deletion dynamic buffer uploads, indexed and non-indexed draws, and resource deletion
now execute through tested `pp_renderer_gl` dispatch contracts, leaving only now execute through tested `pp_renderer_gl` dispatch contracts, leaving only
thin GL adapter functions in the retained shape utility. thin GL adapter functions in the retained shape utility.
Legacy `Font` text mesh creation now covers the one-VAO/deferred-upload case,
and its dynamic index/vertex uploads and indexed draw calls execute through
the same tested dispatch contracts.
- `pp_renderer_gl_command_plan_tests` covers the headless OpenGL command - `pp_renderer_gl_command_plan_tests` covers the headless OpenGL command
planner for recorded render-pass clear masks/values, viewport/scissor state, planner for recorded render-pass clear masks/values, viewport/scissor state,
blend/depth/sampler state, texture format mapping, mesh/draw primitive modes, blend/depth/sampler state, texture format mapping, mesh/draw primitive modes,

View File

@@ -7,6 +7,10 @@
#include "app.h" #include "app.h"
#include "renderer_gl/opengl_capabilities.h" #include "renderer_gl/opengl_capabilities.h"
#include <array>
#include <cstddef>
#include <cstdint>
namespace { namespace {
[[nodiscard]] GLint font_atlas_internal_format() noexcept [[nodiscard]] GLint font_atlas_internal_format() noexcept
@@ -19,46 +23,133 @@ namespace {
return static_cast<GLint>(pp::renderer::gl::texture_format_for_channel_count(1U).pixel_format); return static_cast<GLint>(pp::renderer::gl::texture_format_for_channel_count(1U).pixel_format);
} }
[[nodiscard]] GLenum element_array_buffer_target() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::element_array_buffer_target());
}
[[nodiscard]] GLenum array_buffer_target() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::array_buffer_target());
}
[[nodiscard]] GLenum static_draw_buffer_usage() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::static_draw_buffer_usage());
}
[[nodiscard]] GLenum vertex_attribute_float_component_type() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::vertex_attribute_float_component_type());
}
[[nodiscard]] GLboolean vertex_attribute_not_normalized() noexcept
{
return static_cast<GLboolean>(pp::renderer::gl::vertex_attribute_not_normalized());
}
[[nodiscard]] GLenum text_mesh_primitive_mode() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_fill_count(3U));
}
[[nodiscard]] GLenum text_mesh_index_type() noexcept
{
return static_cast<GLenum>(pp::renderer::gl::index_type_for_index_size(sizeof(GLushort)));
}
[[nodiscard]] GLenum texture_unit(std::uint32_t unit_index) noexcept [[nodiscard]] GLenum texture_unit(std::uint32_t unit_index) noexcept
{ {
return static_cast<GLenum>(pp::renderer::gl::active_texture_unit(unit_index)); return static_cast<GLenum>(pp::renderer::gl::active_texture_unit(unit_index));
} }
void gen_buffers_adapter(std::uint32_t count, std::uint32_t* ids) noexcept
{
glGenBuffers(static_cast<GLsizei>(count), ids);
}
void bind_buffer_adapter(std::uint32_t target, std::uint32_t buffer) noexcept
{
glBindBuffer(static_cast<GLenum>(target), static_cast<GLuint>(buffer));
}
void buffer_data_adapter(
std::uint32_t target,
std::intptr_t byte_count,
const void* data,
std::uint32_t usage) noexcept
{
glBufferData(static_cast<GLenum>(target), static_cast<GLsizeiptr>(byte_count), data, static_cast<GLenum>(usage));
}
void gen_vertex_arrays_adapter(std::uint32_t count, std::uint32_t* ids) noexcept
{
glGenVertexArrays(static_cast<GLsizei>(count), ids);
}
void bind_vertex_array_adapter(std::uint32_t vertex_array) noexcept
{
glBindVertexArray(static_cast<GLuint>(vertex_array));
}
void enable_vertex_attrib_array_adapter(std::uint32_t index) noexcept
{
glEnableVertexAttribArray(static_cast<GLuint>(index));
}
void vertex_attrib_pointer_adapter(
std::uint32_t index,
std::int32_t component_count,
std::uint32_t component_type,
std::uint8_t normalized,
std::int32_t stride,
const void* offset) noexcept
{
glVertexAttribPointer(
static_cast<GLuint>(index),
static_cast<GLint>(component_count),
static_cast<GLenum>(component_type),
static_cast<GLboolean>(normalized),
static_cast<GLsizei>(stride),
offset);
}
void draw_elements_adapter(
std::uint32_t mode,
std::int32_t count,
std::uint32_t index_type,
const void* index_offset) noexcept
{
glDrawElements(
static_cast<GLenum>(mode),
static_cast<GLsizei>(count),
static_cast<GLenum>(index_type),
index_offset);
}
void draw_arrays_adapter(std::uint32_t mode, std::int32_t first, std::int32_t count) noexcept
{
glDrawArrays(static_cast<GLenum>(mode), static_cast<GLint>(first), static_cast<GLsizei>(count));
}
[[nodiscard]] std::span<const pp::renderer::gl::OpenGlVertexAttribute> text_mesh_vertex_attributes() noexcept
{
static const std::array<pp::renderer::gl::OpenGlVertexAttribute, 2> attributes {
pp::renderer::gl::OpenGlVertexAttribute {
.index = 0U,
.component_count = 2,
.component_type = pp::renderer::gl::vertex_attribute_float_component_type(),
.normalized = static_cast<std::uint8_t>(pp::renderer::gl::vertex_attribute_not_normalized()),
.stride = static_cast<std::int32_t>(sizeof(glm::vec4)),
.offset = 0U,
},
pp::renderer::gl::OpenGlVertexAttribute {
.index = 1U,
.component_count = 2,
.component_type = pp::renderer::gl::vertex_attribute_float_component_type(),
.normalized = static_cast<std::uint8_t>(pp::renderer::gl::vertex_attribute_not_normalized()),
.stride = static_cast<std::int32_t>(sizeof(glm::vec4)),
.offset = static_cast<std::uintptr_t>(sizeof(float) * 2),
},
};
return attributes;
}
[[nodiscard]] pp::renderer::gl::OpenGlMeshCreateDispatch text_mesh_create_dispatch() noexcept
{
return pp::renderer::gl::OpenGlMeshCreateDispatch {
.gen_buffers = gen_buffers_adapter,
.bind_buffer = bind_buffer_adapter,
.buffer_data = buffer_data_adapter,
.gen_vertex_arrays = gen_vertex_arrays_adapter,
.bind_vertex_array = bind_vertex_array_adapter,
.enable_vertex_attrib_array = enable_vertex_attrib_array_adapter,
.vertex_attrib_pointer = vertex_attrib_pointer_adapter,
};
}
[[nodiscard]] pp::renderer::gl::OpenGlBufferUploadDispatch text_buffer_upload_dispatch() noexcept
{
return pp::renderer::gl::OpenGlBufferUploadDispatch {
.bind_buffer = bind_buffer_adapter,
.buffer_data = buffer_data_adapter,
};
}
[[nodiscard]] pp::renderer::gl::OpenGlMeshDrawDispatch text_mesh_draw_dispatch() noexcept
{
return pp::renderer::gl::OpenGlMeshDrawDispatch {
.bind_vertex_array = bind_vertex_array_adapter,
.draw_elements = draw_elements_adapter,
.draw_arrays = draw_arrays_adapter,
};
}
} }
std::map<std::string, Font> FontManager::m_fonts; std::map<std::string, Font> FontManager::m_fonts;
@@ -210,18 +301,22 @@ bool TextMesh::create()
{ {
App::I->render_task([this] App::I->render_task([this]
{ {
glGenBuffers(2, font_buffers); const auto mesh = pp::renderer::gl::create_opengl_mesh_objects(
#if USE_VBO pp::renderer::gl::OpenGlMeshUpload {
glGenVertexArrays(1, &font_array); .vertex_data = nullptr,
glBindVertexArray(font_array); .vertex_byte_count = 0,
glEnableVertexAttribArray(0); .index_data = nullptr,
glEnableVertexAttribArray(1); .index_byte_count = 0,
glBindBuffer(element_array_buffer_target(), font_buffers[1]); .indexed = true,
glBindBuffer(array_buffer_target(), font_buffers[0]); .vertex_array_count = 1U,
glVertexAttribPointer(0, 2, vertex_attribute_float_component_type(), vertex_attribute_not_normalized(), sizeof(glm::vec4), (GLvoid*)0); .attributes = text_mesh_vertex_attributes(),
glVertexAttribPointer(1, 2, vertex_attribute_float_component_type(), vertex_attribute_not_normalized(), sizeof(glm::vec4), (GLvoid*)(sizeof(float) * 2)); },
glBindVertexArray(0); text_mesh_create_dispatch());
#endif // USE_VBO if (mesh.ok()) {
font_buffers[0] = static_cast<GLuint>(mesh.value().vertex_buffer);
font_buffers[1] = static_cast<GLuint>(mesh.value().index_buffer);
font_array = static_cast<GLuint>(mesh.value().vertex_arrays[0]);
}
}); });
return true; return true;
} }
@@ -309,12 +404,24 @@ void TextMesh::update(const std::string& text, const std::string& font, int size
font_array_count = (int)idx.size(); font_array_count = (int)idx.size();
App::I->render_task([&] App::I->render_task([&]
{ {
glBindBuffer(element_array_buffer_target(), font_buffers[1]); (void)pp::renderer::gl::upload_opengl_buffer_data(
glBufferData(element_array_buffer_target(), idx.size() * sizeof(GLushort), idx.data(), static_draw_buffer_usage()); pp::renderer::gl::OpenGlBufferUpload {
glBindBuffer(array_buffer_target(), font_buffers[0]); .target = pp::renderer::gl::element_array_buffer_target(),
glBufferData(array_buffer_target(), v.size() * sizeof(glm::vec4), v.data(), static_draw_buffer_usage()); .buffer_id = font_buffers[1],
glBindBuffer(array_buffer_target(), 0); .data = idx.data(),
glBindBuffer(element_array_buffer_target(), 0); .byte_count = static_cast<std::intptr_t>(idx.size() * sizeof(GLushort)),
.usage = pp::renderer::gl::static_draw_buffer_usage(),
},
text_buffer_upload_dispatch());
(void)pp::renderer::gl::upload_opengl_buffer_data(
pp::renderer::gl::OpenGlBufferUpload {
.target = pp::renderer::gl::array_buffer_target(),
.buffer_id = font_buffers[0],
.data = v.data(),
.byte_count = static_cast<std::intptr_t>(v.size() * sizeof(glm::vec4)),
.usage = pp::renderer::gl::static_draw_buffer_usage(),
},
text_buffer_upload_dispatch());
}); });
} }
} }
@@ -328,23 +435,16 @@ void TextMesh::draw()
f.font_tex.bind(); f.font_tex.bind();
FontManager::m_sampler.bind(0); FontManager::m_sampler.bind(0);
#if USE_VBO (void)pp::renderer::gl::draw_opengl_mesh(
glBindVertexArray(font_array); pp::renderer::gl::OpenGlMeshDraw {
glDrawElements(text_mesh_primitive_mode(), font_array_count, text_mesh_index_type(), 0); .vertex_array = font_array,
glBindVertexArray(0); .mode = pp::renderer::gl::primitive_mode_for_fill_count(3U),
#else .count = font_array_count,
glEnableVertexAttribArray(0); .indexed = true,
glEnableVertexAttribArray(1); .index_type = pp::renderer::gl::index_type_for_index_size(sizeof(GLushort)),
glBindBuffer(element_array_buffer_target(), font_buffers[1]); .index_offset = nullptr,
glBindBuffer(array_buffer_target(), font_buffers[0]); },
glVertexAttribPointer(0, 2, vertex_attribute_float_component_type(), vertex_attribute_not_normalized(), sizeof(glm::vec4), (GLvoid*)0); text_mesh_draw_dispatch());
glVertexAttribPointer(1, 2, vertex_attribute_float_component_type(), vertex_attribute_not_normalized(), sizeof(glm::vec4), (GLvoid*)(sizeof(float) * 2));
glDrawElements(text_mesh_primitive_mode(), font_array_count, text_mesh_index_type(), 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(array_buffer_target(), 0);
glBindBuffer(element_array_buffer_target(), 0);
#endif // USE_VBO
f.font_tex.unbind(); f.font_tex.unbind();
FontManager::m_sampler.unbind(); FontManager::m_sampler.unbind();

View File

@@ -1232,8 +1232,11 @@ pp::foundation::Result<OpenGlMeshObjects> create_opengl_mesh_objects(
if (upload.vertex_byte_count < 0 if (upload.vertex_byte_count < 0
|| (upload.vertex_byte_count > 0 && upload.vertex_data == nullptr) || (upload.vertex_byte_count > 0 && upload.vertex_data == nullptr)
|| (upload.indexed && (upload.index_byte_count <= 0 || upload.index_data == nullptr)) || upload.index_byte_count < 0
|| (upload.index_byte_count > 0 && upload.index_data == nullptr)
|| (!upload.indexed && upload.index_byte_count != 0) || (!upload.indexed && upload.index_byte_count != 0)
|| upload.vertex_array_count == 0U
|| upload.vertex_array_count > 2U
|| upload.attributes.empty()) { || upload.attributes.empty()) {
return pp::foundation::Result<OpenGlMeshObjects>::failure( return pp::foundation::Result<OpenGlMeshObjects>::failure(
pp::foundation::Status::invalid_argument("OpenGL mesh upload parameters are invalid")); pp::foundation::Status::invalid_argument("OpenGL mesh upload parameters are invalid"));
@@ -1254,7 +1257,7 @@ pp::foundation::Result<OpenGlMeshObjects> create_opengl_mesh_objects(
pp::foundation::Status::out_of_range("OpenGL mesh buffer allocation returned id 0")); pp::foundation::Status::out_of_range("OpenGL mesh buffer allocation returned id 0"));
} }
if (upload.indexed) { if (upload.indexed && upload.index_byte_count > 0) {
dispatch.bind_buffer(element_array_buffer_target(), buffers[1]); dispatch.bind_buffer(element_array_buffer_target(), buffers[1]);
dispatch.buffer_data(element_array_buffer_target(), upload.index_byte_count, upload.index_data, static_draw_buffer_usage()); dispatch.buffer_data(element_array_buffer_target(), upload.index_byte_count, upload.index_data, static_draw_buffer_usage());
} }
@@ -1266,13 +1269,14 @@ pp::foundation::Result<OpenGlMeshObjects> create_opengl_mesh_objects(
dispatch.bind_buffer(array_buffer_target(), 0U); dispatch.bind_buffer(array_buffer_target(), 0U);
std::array<std::uint32_t, 2> vertex_arrays {}; std::array<std::uint32_t, 2> vertex_arrays {};
dispatch.gen_vertex_arrays(static_cast<std::uint32_t>(vertex_arrays.size()), vertex_arrays.data()); dispatch.gen_vertex_arrays(upload.vertex_array_count, vertex_arrays.data());
if (vertex_arrays[0] == 0U || vertex_arrays[1] == 0U) { if (vertex_arrays[0] == 0U || (upload.vertex_array_count > 1U && vertex_arrays[1] == 0U)) {
return pp::foundation::Result<OpenGlMeshObjects>::failure( return pp::foundation::Result<OpenGlMeshObjects>::failure(
pp::foundation::Status::out_of_range("OpenGL mesh vertex array allocation returned id 0")); pp::foundation::Status::out_of_range("OpenGL mesh vertex array allocation returned id 0"));
} }
for (const auto vertex_array : vertex_arrays) { for (std::uint32_t vertex_array_index = 0U; vertex_array_index < upload.vertex_array_count; ++vertex_array_index) {
const auto vertex_array = vertex_arrays[vertex_array_index];
dispatch.bind_vertex_array(vertex_array); dispatch.bind_vertex_array(vertex_array);
for (const auto& attribute : upload.attributes) { for (const auto& attribute : upload.attributes) {
dispatch.enable_vertex_attrib_array(attribute.index); dispatch.enable_vertex_attrib_array(attribute.index);

View File

@@ -183,6 +183,7 @@ struct OpenGlMeshUpload {
const void* index_data = nullptr; const void* index_data = nullptr;
std::intptr_t index_byte_count = 0; std::intptr_t index_byte_count = 0;
bool indexed = false; bool indexed = false;
std::uint32_t vertex_array_count = 2;
std::span<const OpenGlVertexAttribute> attributes; std::span<const OpenGlVertexAttribute> attributes;
}; };

View File

@@ -3059,6 +3059,76 @@ void creates_dynamic_mesh_without_initial_vertex_upload(pp::tests::Harness& h)
PP_EXPECT(h, recorded_vertex_array_bind_calls.size() == 3U); PP_EXPECT(h, recorded_vertex_array_bind_calls.size() == 3U);
} }
void creates_single_vertex_array_mesh_with_deferred_upload(pp::tests::Harness& h)
{
recorded_generated_buffer_counts.clear();
recorded_generated_vertex_array_counts.clear();
recorded_buffer_bind_calls.clear();
recorded_buffer_data_calls.clear();
recorded_vertex_array_bind_calls.clear();
recorded_enabled_vertex_attributes.clear();
recorded_vertex_attrib_pointer_calls.clear();
next_buffer_id = 901U;
next_vertex_array_id = 1001U;
constexpr std::array attributes {
pp::renderer::gl::OpenGlVertexAttribute {
.index = 0U,
.component_count = 2,
.component_type = 0x1406U,
.normalized = 0U,
.stride = 16,
.offset = 0U,
},
pp::renderer::gl::OpenGlVertexAttribute {
.index = 1U,
.component_count = 2,
.component_type = 0x1406U,
.normalized = 0U,
.stride = 16,
.offset = 8U,
},
};
const auto mesh = pp::renderer::gl::create_opengl_mesh_objects(
pp::renderer::gl::OpenGlMeshUpload {
.vertex_data = nullptr,
.vertex_byte_count = 0,
.index_data = nullptr,
.index_byte_count = 0,
.indexed = true,
.vertex_array_count = 1U,
.attributes = attributes,
},
pp::renderer::gl::OpenGlMeshCreateDispatch {
.gen_buffers = record_gen_buffers,
.bind_buffer = record_bind_buffer,
.buffer_data = record_buffer_data,
.gen_vertex_arrays = record_gen_vertex_arrays,
.bind_vertex_array = record_bind_vertex_array,
.enable_vertex_attrib_array = record_enable_vertex_attrib_array,
.vertex_attrib_pointer = record_vertex_attrib_pointer,
});
PP_EXPECT(h, mesh.ok());
PP_EXPECT(h, mesh.value().vertex_buffer == 901U);
PP_EXPECT(h, mesh.value().index_buffer == 902U);
PP_EXPECT(h, mesh.value().vertex_arrays[0] == 1001U);
PP_EXPECT(h, mesh.value().vertex_arrays[1] == 0U);
PP_EXPECT(h, recorded_generated_buffer_counts.size() == 1U);
PP_EXPECT(h, recorded_generated_buffer_counts[0] == 2U);
PP_EXPECT(h, recorded_generated_vertex_array_counts.size() == 1U);
PP_EXPECT(h, recorded_generated_vertex_array_counts[0] == 1U);
PP_EXPECT(h, recorded_buffer_data_calls.empty());
PP_EXPECT(h, recorded_vertex_array_bind_calls.size() == 2U);
PP_EXPECT(h, recorded_vertex_array_bind_calls[0] == 1001U);
PP_EXPECT(h, recorded_vertex_array_bind_calls[1] == 0U);
PP_EXPECT(h, recorded_enabled_vertex_attributes.size() == 2U);
PP_EXPECT(h, recorded_vertex_attrib_pointer_calls.size() == 2U);
PP_EXPECT(h, recorded_vertex_attrib_pointer_calls[0].index == 0U);
PP_EXPECT(h, recorded_vertex_attrib_pointer_calls[1].offset == reinterpret_cast<const void*>(8U));
}
void updates_draws_and_deletes_mesh_through_dispatch(pp::tests::Harness& h) void updates_draws_and_deletes_mesh_through_dispatch(pp::tests::Harness& h)
{ {
recorded_buffer_bind_calls.clear(); recorded_buffer_bind_calls.clear();
@@ -3212,6 +3282,22 @@ void rejects_invalid_mesh_dispatch(pp::tests::Harness& h)
.enable_vertex_attrib_array = record_enable_vertex_attrib_array, .enable_vertex_attrib_array = record_enable_vertex_attrib_array,
.vertex_attrib_pointer = record_vertex_attrib_pointer, .vertex_attrib_pointer = record_vertex_attrib_pointer,
}); });
const auto invalid_vertex_array_count = pp::renderer::gl::create_opengl_mesh_objects(
pp::renderer::gl::OpenGlMeshUpload {
.vertex_data = vertices.data(),
.vertex_byte_count = static_cast<std::intptr_t>(sizeof(float) * vertices.size()),
.vertex_array_count = 3U,
.attributes = attributes,
},
pp::renderer::gl::OpenGlMeshCreateDispatch {
.gen_buffers = record_gen_buffers,
.bind_buffer = record_bind_buffer,
.buffer_data = record_buffer_data,
.gen_vertex_arrays = record_gen_vertex_arrays,
.bind_vertex_array = record_bind_vertex_array,
.enable_vertex_attrib_array = record_enable_vertex_attrib_array,
.vertex_attrib_pointer = record_vertex_attrib_pointer,
});
const auto missing_upload_dispatch = pp::renderer::gl::upload_opengl_buffer_data( const auto missing_upload_dispatch = pp::renderer::gl::upload_opengl_buffer_data(
pp::renderer::gl::OpenGlBufferUpload { pp::renderer::gl::OpenGlBufferUpload {
.target = 0x8892U, .target = 0x8892U,
@@ -3261,6 +3347,8 @@ void rejects_invalid_mesh_dispatch(pp::tests::Harness& h)
PP_EXPECT(h, invalid_create_data.status().code == pp::foundation::StatusCode::invalid_argument); PP_EXPECT(h, invalid_create_data.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_attribute.ok()); PP_EXPECT(h, !invalid_attribute.ok());
PP_EXPECT(h, invalid_attribute.status().code == pp::foundation::StatusCode::invalid_argument); PP_EXPECT(h, invalid_attribute.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_vertex_array_count.ok());
PP_EXPECT(h, invalid_vertex_array_count.status().code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !missing_upload_dispatch.ok()); PP_EXPECT(h, !missing_upload_dispatch.ok());
PP_EXPECT(h, missing_upload_dispatch.code == pp::foundation::StatusCode::invalid_argument); PP_EXPECT(h, missing_upload_dispatch.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(h, !invalid_upload.ok()); PP_EXPECT(h, !invalid_upload.ok());
@@ -4069,6 +4157,7 @@ int main()
harness.run("rejects_invalid_uniform_discovery_dispatch", rejects_invalid_uniform_discovery_dispatch); harness.run("rejects_invalid_uniform_discovery_dispatch", rejects_invalid_uniform_discovery_dispatch);
harness.run("creates_indexed_mesh_objects_through_dispatch", creates_indexed_mesh_objects_through_dispatch); harness.run("creates_indexed_mesh_objects_through_dispatch", creates_indexed_mesh_objects_through_dispatch);
harness.run("creates_dynamic_mesh_without_initial_vertex_upload", creates_dynamic_mesh_without_initial_vertex_upload); harness.run("creates_dynamic_mesh_without_initial_vertex_upload", creates_dynamic_mesh_without_initial_vertex_upload);
harness.run("creates_single_vertex_array_mesh_with_deferred_upload", creates_single_vertex_array_mesh_with_deferred_upload);
harness.run("updates_draws_and_deletes_mesh_through_dispatch", updates_draws_and_deletes_mesh_through_dispatch); harness.run("updates_draws_and_deletes_mesh_through_dispatch", updates_draws_and_deletes_mesh_through_dispatch);
harness.run("rejects_invalid_mesh_dispatch", rejects_invalid_mesh_dispatch); harness.run("rejects_invalid_mesh_dispatch", rejects_invalid_mesh_dispatch);
harness.run("updates_texture_2d_through_dispatch", updates_texture_2d_through_dispatch); harness.run("updates_texture_2d_through_dispatch", updates_texture_2d_through_dispatch);