Route shader creation through renderer GL
This commit is contained in:
@@ -228,8 +228,11 @@ Known local toolchain state:
|
|||||||
names directly. It also owns the PanoPainter shader uniform catalog and legacy hash
|
names directly. It also owns the PanoPainter shader uniform catalog and legacy hash
|
||||||
mapping used by `Shader` active-uniform discovery and the uniform uniqueness
|
mapping used by `Shader` active-uniform discovery and the uniform uniqueness
|
||||||
check. Legacy `Shader` program use/delete, uniform writes, and
|
check. Legacy `Shader` program use/delete, uniform writes, and
|
||||||
attribute-location lookup now consume tested dispatch contracts here;
|
attribute-location lookup now consume tested dispatch contracts here.
|
||||||
compile/link and active-uniform discovery are still retained legacy GL calls.
|
Legacy shader source compilation, shader deletion, program attach/link,
|
||||||
|
attribute rebinding, active-uniform count/enumeration, and uniform-location
|
||||||
|
discovery now consume tested dispatch contracts as well, leaving the retained
|
||||||
|
shader utility with thin GL adapter functions.
|
||||||
App OpenGL initialization debug severity, debug output, GL info string,
|
App OpenGL initialization debug severity, debug output, GL info string,
|
||||||
renderer API viewport/scissor rect conversion, default depth/program-point/
|
renderer API viewport/scissor rect conversion, default depth/program-point/
|
||||||
line-smooth state, blend factor/equation, and UI render-target RGBA8 format
|
line-smooth state, blend factor/equation, and UI render-target RGBA8 format
|
||||||
|
|||||||
@@ -1120,9 +1120,11 @@ Results:
|
|||||||
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.
|
||||||
Legacy `Shader` program use/delete, uniform writes, and attribute-location
|
Legacy `Shader` program use/delete, uniform writes, and attribute-location
|
||||||
lookups now execute through tested `pp_renderer_gl` dispatch contracts;
|
lookups now execute through tested `pp_renderer_gl` dispatch contracts.
|
||||||
shader compile/link and active-uniform discovery remain the next shader
|
Legacy shader source compilation, shader deletion, program attach/link,
|
||||||
boundary work.
|
attribute rebinding, active-uniform count/enumeration, and uniform-location
|
||||||
|
discovery also execute through tested `pp_renderer_gl` dispatch contracts,
|
||||||
|
leaving only thin GL adapter functions in the retained `Shader` utility.
|
||||||
- `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,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "renderer_gl/opengl_capabilities.h"
|
#include "renderer_gl/opengl_capabilities.h"
|
||||||
|
#include "renderer_gl/shader_bindings.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@@ -1030,6 +1031,190 @@ pp::foundation::Result<std::int32_t> get_opengl_attribute_location(
|
|||||||
dispatch.get_attrib_location(program_id, attribute_name));
|
dispatch.get_attrib_location(program_id, attribute_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<OpenGlShaderCompileInfo> compile_opengl_shader_source(
|
||||||
|
std::uint32_t stage,
|
||||||
|
const char* source,
|
||||||
|
char* info_log,
|
||||||
|
std::int32_t info_log_capacity,
|
||||||
|
OpenGlShaderCompileDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.create_shader == nullptr
|
||||||
|
|| dispatch.shader_source == nullptr
|
||||||
|
|| dispatch.compile_shader == nullptr
|
||||||
|
|| dispatch.get_shader_integer == nullptr
|
||||||
|
|| dispatch.get_shader_info_log == nullptr) {
|
||||||
|
return pp::foundation::Result<OpenGlShaderCompileInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL shader compile dispatch callbacks must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stage == 0U || source == nullptr || source[0] == '\0' || info_log == nullptr || info_log_capacity <= 0) {
|
||||||
|
return pp::foundation::Result<OpenGlShaderCompileInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL shader compile parameters are invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto shader_id = dispatch.create_shader(stage);
|
||||||
|
if (shader_id == 0U) {
|
||||||
|
return pp::foundation::Result<OpenGlShaderCompileInfo>::failure(
|
||||||
|
pp::foundation::Status::out_of_range("OpenGL shader allocation returned id 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const sources[] { source };
|
||||||
|
dispatch.shader_source(shader_id, 1, sources);
|
||||||
|
dispatch.compile_shader(shader_id);
|
||||||
|
|
||||||
|
OpenGlShaderCompileInfo info {
|
||||||
|
.shader_id = shader_id,
|
||||||
|
};
|
||||||
|
dispatch.get_shader_integer(shader_id, shader_compile_status_query(), &info.compile_status);
|
||||||
|
dispatch.get_shader_info_log(shader_id, info_log_capacity, &info.info_log_length, info_log);
|
||||||
|
return pp::foundation::Result<OpenGlShaderCompileInfo>::success(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status delete_opengl_shader(
|
||||||
|
std::uint32_t shader_id,
|
||||||
|
OpenGlShaderDeleteDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.delete_shader == nullptr) {
|
||||||
|
return pp::foundation::Status::invalid_argument("OpenGL shader delete dispatch callback must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shader_id == 0U) {
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.delete_shader(shader_id);
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<OpenGlProgramLinkInfo> link_opengl_shader_program(
|
||||||
|
std::uint32_t vertex_shader_id,
|
||||||
|
std::uint32_t fragment_shader_id,
|
||||||
|
std::span<const OpenGlAttributeBinding> attribute_bindings,
|
||||||
|
char* info_log,
|
||||||
|
std::int32_t info_log_capacity,
|
||||||
|
OpenGlProgramLinkDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.create_program == nullptr
|
||||||
|
|| dispatch.attach_shader == nullptr
|
||||||
|
|| dispatch.delete_shader == nullptr
|
||||||
|
|| dispatch.link_program == nullptr
|
||||||
|
|| dispatch.get_attrib_location == nullptr
|
||||||
|
|| dispatch.bind_attrib_location == nullptr
|
||||||
|
|| dispatch.get_program_integer == nullptr
|
||||||
|
|| dispatch.get_program_info_log == nullptr) {
|
||||||
|
return pp::foundation::Result<OpenGlProgramLinkInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL program link dispatch callbacks must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertex_shader_id == 0U
|
||||||
|
|| fragment_shader_id == 0U
|
||||||
|
|| attribute_bindings.empty()
|
||||||
|
|| info_log == nullptr
|
||||||
|
|| info_log_capacity <= 0) {
|
||||||
|
return pp::foundation::Result<OpenGlProgramLinkInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL program link parameters are invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto program_id = dispatch.create_program();
|
||||||
|
if (program_id == 0U) {
|
||||||
|
return pp::foundation::Result<OpenGlProgramLinkInfo>::failure(
|
||||||
|
pp::foundation::Status::out_of_range("OpenGL program allocation returned id 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.attach_shader(program_id, vertex_shader_id);
|
||||||
|
dispatch.attach_shader(program_id, fragment_shader_id);
|
||||||
|
dispatch.delete_shader(vertex_shader_id);
|
||||||
|
dispatch.delete_shader(fragment_shader_id);
|
||||||
|
dispatch.link_program(program_id);
|
||||||
|
|
||||||
|
for (const auto& binding : attribute_bindings) {
|
||||||
|
if (binding.name != nullptr && dispatch.get_attrib_location(program_id, binding.name) != -1) {
|
||||||
|
dispatch.bind_attrib_location(program_id, binding.location, binding.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlProgramLinkInfo info {
|
||||||
|
.program_id = program_id,
|
||||||
|
};
|
||||||
|
dispatch.link_program(program_id);
|
||||||
|
dispatch.get_program_integer(program_id, program_link_status_query(), &info.link_status);
|
||||||
|
dispatch.get_program_info_log(program_id, info_log_capacity, &info.info_log_length, info_log);
|
||||||
|
return pp::foundation::Result<OpenGlProgramLinkInfo>::success(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<std::int32_t> query_opengl_program_integer(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
std::uint32_t query,
|
||||||
|
OpenGlProgramIntegerDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.get_program_integer == nullptr) {
|
||||||
|
return pp::foundation::Result<std::int32_t>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL program integer dispatch callback must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program_id == 0U || query == 0U) {
|
||||||
|
return pp::foundation::Result<std::int32_t>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL program integer parameters are invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t value = 0;
|
||||||
|
dispatch.get_program_integer(program_id, query, &value);
|
||||||
|
return pp::foundation::Result<std::int32_t>::success(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<OpenGlActiveUniformInfo> get_opengl_active_uniform(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
std::uint32_t index,
|
||||||
|
char* name,
|
||||||
|
std::int32_t name_capacity,
|
||||||
|
OpenGlActiveUniformDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.get_active_uniform == nullptr) {
|
||||||
|
return pp::foundation::Result<OpenGlActiveUniformInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL active uniform dispatch callback must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program_id == 0U || name == nullptr || name_capacity <= 0) {
|
||||||
|
return pp::foundation::Result<OpenGlActiveUniformInfo>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL active uniform parameters are invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGlActiveUniformInfo info {};
|
||||||
|
dispatch.get_active_uniform(
|
||||||
|
program_id,
|
||||||
|
index,
|
||||||
|
name_capacity,
|
||||||
|
&info.length,
|
||||||
|
&info.size,
|
||||||
|
&info.type,
|
||||||
|
name);
|
||||||
|
if (info.length >= 0 && info.length < name_capacity) {
|
||||||
|
name[info.length] = '\0';
|
||||||
|
} else {
|
||||||
|
name[name_capacity - 1] = '\0';
|
||||||
|
}
|
||||||
|
return pp::foundation::Result<OpenGlActiveUniformInfo>::success(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<std::int32_t> get_opengl_uniform_location(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
const char* uniform_name,
|
||||||
|
OpenGlUniformLocationDispatch dispatch) noexcept
|
||||||
|
{
|
||||||
|
if (dispatch.get_uniform_location == nullptr) {
|
||||||
|
return pp::foundation::Result<std::int32_t>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL uniform-location dispatch callback must not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program_id == 0U || uniform_name == nullptr || uniform_name[0] == '\0') {
|
||||||
|
return pp::foundation::Result<std::int32_t>::failure(
|
||||||
|
pp::foundation::Status::invalid_argument("OpenGL uniform-location parameters are invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Result<std::int32_t>::success(
|
||||||
|
dispatch.get_uniform_location(program_id, uniform_name));
|
||||||
|
}
|
||||||
|
|
||||||
std::uint32_t extension_count_query() noexcept
|
std::uint32_t extension_count_query() noexcept
|
||||||
{
|
{
|
||||||
return gl_num_extensions;
|
return gl_num_extensions;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
namespace pp::renderer::gl {
|
namespace pp::renderer::gl {
|
||||||
|
|
||||||
|
struct OpenGlAttributeBinding;
|
||||||
|
|
||||||
struct OpenGlRuntime {
|
struct OpenGlRuntime {
|
||||||
bool desktop_gl = false;
|
bool desktop_gl = false;
|
||||||
bool gles = false;
|
bool gles = false;
|
||||||
@@ -148,6 +150,24 @@ struct OpenGlTexture2DReadbackResult {
|
|||||||
bool pixels_read = false;
|
bool pixels_read = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlShaderCompileInfo {
|
||||||
|
std::uint32_t shader_id = 0;
|
||||||
|
std::int32_t compile_status = 0;
|
||||||
|
std::int32_t info_log_length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlProgramLinkInfo {
|
||||||
|
std::uint32_t program_id = 0;
|
||||||
|
std::int32_t link_status = 0;
|
||||||
|
std::int32_t info_log_length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlActiveUniformInfo {
|
||||||
|
std::int32_t length = 0;
|
||||||
|
std::int32_t size = 0;
|
||||||
|
std::uint32_t type = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct OpenGlFramebufferRect {
|
struct OpenGlFramebufferRect {
|
||||||
std::int32_t x0 = 0;
|
std::int32_t x0 = 0;
|
||||||
std::int32_t y0 = 0;
|
std::int32_t y0 = 0;
|
||||||
@@ -232,6 +252,47 @@ using OpenGlUniformMatrix4fvFn = void (*)(
|
|||||||
using OpenGlUniform1iFn = void (*)(std::int32_t location, std::int32_t value) noexcept;
|
using OpenGlUniform1iFn = void (*)(std::int32_t location, std::int32_t value) noexcept;
|
||||||
using OpenGlUniform1fFn = void (*)(std::int32_t location, float value) noexcept;
|
using OpenGlUniform1fFn = void (*)(std::int32_t location, float value) noexcept;
|
||||||
using OpenGlGetAttribLocationFn = std::int32_t (*)(std::uint32_t program, const char* name) noexcept;
|
using OpenGlGetAttribLocationFn = std::int32_t (*)(std::uint32_t program, const char* name) noexcept;
|
||||||
|
using OpenGlCreateShaderFn = std::uint32_t (*)(std::uint32_t stage) noexcept;
|
||||||
|
using OpenGlShaderSourceFn = void (*)(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::int32_t count,
|
||||||
|
const char* const* sources) noexcept;
|
||||||
|
using OpenGlCompileShaderFn = void (*)(std::uint32_t shader) noexcept;
|
||||||
|
using OpenGlGetShaderIntegerFn = void (*)(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::uint32_t query,
|
||||||
|
std::int32_t* value) noexcept;
|
||||||
|
using OpenGlGetShaderInfoLogFn = void (*)(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept;
|
||||||
|
using OpenGlDeleteShaderFn = void (*)(std::uint32_t shader) noexcept;
|
||||||
|
using OpenGlCreateProgramFn = std::uint32_t (*)() noexcept;
|
||||||
|
using OpenGlAttachShaderFn = void (*)(std::uint32_t program, std::uint32_t shader) noexcept;
|
||||||
|
using OpenGlLinkProgramFn = void (*)(std::uint32_t program) noexcept;
|
||||||
|
using OpenGlBindAttribLocationFn = void (*)(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t location,
|
||||||
|
const char* name) noexcept;
|
||||||
|
using OpenGlGetProgramIntegerFn = void (*)(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t query,
|
||||||
|
std::int32_t* value) noexcept;
|
||||||
|
using OpenGlGetProgramInfoLogFn = void (*)(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept;
|
||||||
|
using OpenGlGetActiveUniformFn = void (*)(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t index,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
std::int32_t* size,
|
||||||
|
std::uint32_t* type,
|
||||||
|
char* name) noexcept;
|
||||||
|
using OpenGlGetUniformLocationFn = std::int32_t (*)(std::uint32_t program, const char* name) noexcept;
|
||||||
using OpenGlBindFramebufferFn = void (*)(std::uint32_t target, std::uint32_t framebuffer) noexcept;
|
using OpenGlBindFramebufferFn = void (*)(std::uint32_t target, std::uint32_t framebuffer) noexcept;
|
||||||
using OpenGlBindTextureFn = void (*)(std::uint32_t target, std::uint32_t texture) noexcept;
|
using OpenGlBindTextureFn = void (*)(std::uint32_t target, std::uint32_t texture) noexcept;
|
||||||
using OpenGlBindSamplerFn = void (*)(std::uint32_t unit, std::uint32_t sampler) noexcept;
|
using OpenGlBindSamplerFn = void (*)(std::uint32_t unit, std::uint32_t sampler) noexcept;
|
||||||
@@ -482,6 +543,41 @@ struct OpenGlAttributeLocationDispatch {
|
|||||||
OpenGlGetAttribLocationFn get_attrib_location = nullptr;
|
OpenGlGetAttribLocationFn get_attrib_location = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpenGlShaderCompileDispatch {
|
||||||
|
OpenGlCreateShaderFn create_shader = nullptr;
|
||||||
|
OpenGlShaderSourceFn shader_source = nullptr;
|
||||||
|
OpenGlCompileShaderFn compile_shader = nullptr;
|
||||||
|
OpenGlGetShaderIntegerFn get_shader_integer = nullptr;
|
||||||
|
OpenGlGetShaderInfoLogFn get_shader_info_log = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlShaderDeleteDispatch {
|
||||||
|
OpenGlDeleteShaderFn delete_shader = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlProgramLinkDispatch {
|
||||||
|
OpenGlCreateProgramFn create_program = nullptr;
|
||||||
|
OpenGlAttachShaderFn attach_shader = nullptr;
|
||||||
|
OpenGlDeleteShaderFn delete_shader = nullptr;
|
||||||
|
OpenGlLinkProgramFn link_program = nullptr;
|
||||||
|
OpenGlGetAttribLocationFn get_attrib_location = nullptr;
|
||||||
|
OpenGlBindAttribLocationFn bind_attrib_location = nullptr;
|
||||||
|
OpenGlGetProgramIntegerFn get_program_integer = nullptr;
|
||||||
|
OpenGlGetProgramInfoLogFn get_program_info_log = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlProgramIntegerDispatch {
|
||||||
|
OpenGlGetProgramIntegerFn get_program_integer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlActiveUniformDispatch {
|
||||||
|
OpenGlGetActiveUniformFn get_active_uniform = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OpenGlUniformLocationDispatch {
|
||||||
|
OpenGlGetUniformLocationFn get_uniform_location = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
|
[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
|
||||||
std::span<const std::string_view> extensions,
|
std::span<const std::string_view> extensions,
|
||||||
OpenGlRuntime runtime) noexcept;
|
OpenGlRuntime runtime) noexcept;
|
||||||
@@ -603,6 +699,36 @@ struct OpenGlAttributeLocationDispatch {
|
|||||||
std::uint32_t program_id,
|
std::uint32_t program_id,
|
||||||
const char* attribute_name,
|
const char* attribute_name,
|
||||||
OpenGlAttributeLocationDispatch dispatch) noexcept;
|
OpenGlAttributeLocationDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<OpenGlShaderCompileInfo> compile_opengl_shader_source(
|
||||||
|
std::uint32_t stage,
|
||||||
|
const char* source,
|
||||||
|
char* info_log,
|
||||||
|
std::int32_t info_log_capacity,
|
||||||
|
OpenGlShaderCompileDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Status delete_opengl_shader(
|
||||||
|
std::uint32_t shader_id,
|
||||||
|
OpenGlShaderDeleteDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<OpenGlProgramLinkInfo> link_opengl_shader_program(
|
||||||
|
std::uint32_t vertex_shader_id,
|
||||||
|
std::uint32_t fragment_shader_id,
|
||||||
|
std::span<const OpenGlAttributeBinding> attribute_bindings,
|
||||||
|
char* info_log,
|
||||||
|
std::int32_t info_log_capacity,
|
||||||
|
OpenGlProgramLinkDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<std::int32_t> query_opengl_program_integer(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
std::uint32_t query,
|
||||||
|
OpenGlProgramIntegerDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<OpenGlActiveUniformInfo> get_opengl_active_uniform(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
std::uint32_t index,
|
||||||
|
char* name,
|
||||||
|
std::int32_t name_capacity,
|
||||||
|
OpenGlActiveUniformDispatch dispatch) noexcept;
|
||||||
|
[[nodiscard]] pp::foundation::Result<std::int32_t> get_opengl_uniform_location(
|
||||||
|
std::uint32_t program_id,
|
||||||
|
const char* uniform_name,
|
||||||
|
OpenGlUniformLocationDispatch dispatch) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] std::uint32_t extension_count_query() noexcept;
|
[[nodiscard]] std::uint32_t extension_count_query() noexcept;
|
||||||
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
|
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
|
||||||
|
|||||||
342
src/shader.cpp
342
src/shader.cpp
@@ -88,6 +88,125 @@ std::int32_t get_opengl_attrib_location(std::uint32_t program, const char* name)
|
|||||||
return static_cast<std::int32_t>(glGetAttribLocation(static_cast<GLuint>(program), name));
|
return static_cast<std::int32_t>(glGetAttribLocation(static_cast<GLuint>(program), name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint32_t create_opengl_shader(std::uint32_t stage) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(glCreateShader(static_cast<GLenum>(stage)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_opengl_shader_source(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::int32_t count,
|
||||||
|
const char* const* sources) noexcept
|
||||||
|
{
|
||||||
|
glShaderSource(
|
||||||
|
static_cast<GLuint>(shader),
|
||||||
|
static_cast<GLsizei>(count),
|
||||||
|
reinterpret_cast<const GLchar* const*>(sources),
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_opengl_shader(std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
glCompileShader(static_cast<GLuint>(shader));
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_opengl_shader_integer(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::uint32_t query,
|
||||||
|
std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
glGetShaderiv(
|
||||||
|
static_cast<GLuint>(shader),
|
||||||
|
static_cast<GLenum>(query),
|
||||||
|
reinterpret_cast<GLint*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_opengl_shader_info_log(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(
|
||||||
|
static_cast<GLuint>(shader),
|
||||||
|
static_cast<GLsizei>(capacity),
|
||||||
|
reinterpret_cast<GLsizei*>(length),
|
||||||
|
reinterpret_cast<GLchar*>(info_log));
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_opengl_shader(std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
glDeleteShader(static_cast<GLuint>(shader));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t create_opengl_program() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(glCreateProgram());
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach_opengl_shader(std::uint32_t program, std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
glAttachShader(static_cast<GLuint>(program), static_cast<GLuint>(shader));
|
||||||
|
}
|
||||||
|
|
||||||
|
void link_opengl_program(std::uint32_t program) noexcept
|
||||||
|
{
|
||||||
|
glLinkProgram(static_cast<GLuint>(program));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_opengl_attrib_location(std::uint32_t program, std::uint32_t location, const char* name) noexcept
|
||||||
|
{
|
||||||
|
glBindAttribLocation(static_cast<GLuint>(program), static_cast<GLuint>(location), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_opengl_program_integer(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t query,
|
||||||
|
std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
glGetProgramiv(
|
||||||
|
static_cast<GLuint>(program),
|
||||||
|
static_cast<GLenum>(query),
|
||||||
|
reinterpret_cast<GLint*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_opengl_program_info_log(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept
|
||||||
|
{
|
||||||
|
glGetProgramInfoLog(
|
||||||
|
static_cast<GLuint>(program),
|
||||||
|
static_cast<GLsizei>(capacity),
|
||||||
|
reinterpret_cast<GLsizei*>(length),
|
||||||
|
reinterpret_cast<GLchar*>(info_log));
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_opengl_active_uniform(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t index,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
std::int32_t* size,
|
||||||
|
std::uint32_t* type,
|
||||||
|
char* name) noexcept
|
||||||
|
{
|
||||||
|
glGetActiveUniform(
|
||||||
|
static_cast<GLuint>(program),
|
||||||
|
static_cast<GLuint>(index),
|
||||||
|
static_cast<GLsizei>(capacity),
|
||||||
|
reinterpret_cast<GLsizei*>(length),
|
||||||
|
reinterpret_cast<GLint*>(size),
|
||||||
|
reinterpret_cast<GLenum*>(type),
|
||||||
|
reinterpret_cast<GLchar*>(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t get_opengl_uniform_location(std::uint32_t program, const char* name) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::int32_t>(glGetUniformLocation(static_cast<GLuint>(program), name));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<kShader, Shader> ShaderManager::m_shaders;
|
std::map<kShader, Shader> ShaderManager::m_shaders;
|
||||||
@@ -247,113 +366,212 @@ bool Shader::create(const std::string& vertex, const std::string& fragment)
|
|||||||
bool ret = true;
|
bool ret = true;
|
||||||
App::I->render_task([this, &ret, vertex, fragment]
|
App::I->render_task([this, &ret, vertex, fragment]
|
||||||
{
|
{
|
||||||
GLint status;
|
|
||||||
static char infolog[4096];
|
static char infolog[4096];
|
||||||
int infolen;
|
const auto vertex_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
const GLchar* source;
|
pp::renderer::gl::vertex_shader_stage(),
|
||||||
|
vertex.c_str(),
|
||||||
auto vs = glCreateShader(vertex_shader_stage());
|
infolog,
|
||||||
if (!vs)
|
static_cast<std::int32_t>(sizeof(infolog)),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = create_opengl_shader,
|
||||||
|
.shader_source = set_opengl_shader_source,
|
||||||
|
.compile_shader = compile_opengl_shader,
|
||||||
|
.get_shader_integer = query_opengl_shader_integer,
|
||||||
|
.get_shader_info_log = get_opengl_shader_info_log,
|
||||||
|
});
|
||||||
|
if (!vertex_shader.ok())
|
||||||
{
|
{
|
||||||
ret = false;
|
ret = false;
|
||||||
|
LOG("Shader::create() vertex compile failed because: %s", vertex_shader.status().message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
source = vertex.c_str();
|
if (vertex_shader.value().info_log_length > 0)
|
||||||
glShaderSource(vs, 1, &source, nullptr);
|
|
||||||
glCompileShader(vs);
|
|
||||||
glGetShaderiv(vs, shader_compile_status_query(), &status);
|
|
||||||
glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
{
|
{
|
||||||
LOG("\nVERTEX SHADER: %s", m_path.c_str());
|
LOG("\nVERTEX SHADER: %s", m_path.c_str());
|
||||||
parse_error(infolog, vertex);
|
parse_error(infolog, vertex);
|
||||||
}
|
}
|
||||||
if (status == 0)
|
if (vertex_shader.value().compile_status == 0)
|
||||||
{
|
{
|
||||||
glDeleteShader(vs);
|
const auto status = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
vertex_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("Shader::create() vertex shader cleanup failed because: %s", status.message);
|
||||||
ret = false;
|
ret = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fs = glCreateShader(fragment_shader_stage());
|
const auto fragment_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
if (!fs)
|
pp::renderer::gl::fragment_shader_stage(),
|
||||||
|
fragment.c_str(),
|
||||||
|
infolog,
|
||||||
|
static_cast<std::int32_t>(sizeof(infolog)),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = create_opengl_shader,
|
||||||
|
.shader_source = set_opengl_shader_source,
|
||||||
|
.compile_shader = compile_opengl_shader,
|
||||||
|
.get_shader_integer = query_opengl_shader_integer,
|
||||||
|
.get_shader_info_log = get_opengl_shader_info_log,
|
||||||
|
});
|
||||||
|
if (!fragment_shader.ok())
|
||||||
{
|
{
|
||||||
glDeleteShader(vs);
|
const auto status = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
vertex_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("Shader::create() vertex shader cleanup failed because: %s", status.message);
|
||||||
ret = false;
|
ret = false;
|
||||||
|
LOG("Shader::create() fragment compile failed because: %s", fragment_shader.status().message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
source = fragment.c_str();
|
if (fragment_shader.value().info_log_length > 0)
|
||||||
glShaderSource(fs, 1, &source, nullptr);
|
|
||||||
glCompileShader(fs);
|
|
||||||
glGetShaderiv(fs, shader_compile_status_query(), &status);
|
|
||||||
glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
{
|
{
|
||||||
LOG("\nFRAGMENT SHADER: %s", m_path.c_str());
|
LOG("\nFRAGMENT SHADER: %s", m_path.c_str());
|
||||||
parse_error(infolog, fragment);
|
parse_error(infolog, fragment);
|
||||||
}
|
}
|
||||||
if (status == 0)
|
if (fragment_shader.value().compile_status == 0)
|
||||||
{
|
{
|
||||||
glDeleteShader(vs);
|
const auto vertex_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||||
glDeleteShader(fs);
|
vertex_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
const auto fragment_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
fragment_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
if (!vertex_cleanup.ok())
|
||||||
|
LOG("Shader::create() vertex shader cleanup failed because: %s", vertex_cleanup.message);
|
||||||
|
if (!fragment_cleanup.ok())
|
||||||
|
LOG("Shader::create() fragment shader cleanup failed because: %s", fragment_cleanup.message);
|
||||||
ret = false;
|
ret = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ps = glCreateProgram();
|
const auto program = pp::renderer::gl::link_opengl_shader_program(
|
||||||
if (!ps)
|
vertex_shader.value().shader_id,
|
||||||
|
fragment_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||||
|
infolog,
|
||||||
|
static_cast<std::int32_t>(sizeof(infolog)),
|
||||||
|
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||||
|
.create_program = create_opengl_program,
|
||||||
|
.attach_shader = attach_opengl_shader,
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
.link_program = link_opengl_program,
|
||||||
|
.get_attrib_location = get_opengl_attrib_location,
|
||||||
|
.bind_attrib_location = bind_opengl_attrib_location,
|
||||||
|
.get_program_integer = query_opengl_program_integer,
|
||||||
|
.get_program_info_log = get_opengl_program_info_log,
|
||||||
|
});
|
||||||
|
if (!program.ok())
|
||||||
{
|
{
|
||||||
glDeleteShader(vs);
|
const auto vertex_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||||
glDeleteShader(fs);
|
vertex_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
const auto fragment_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
fragment_shader.value().shader_id,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = delete_opengl_shader,
|
||||||
|
});
|
||||||
|
if (!vertex_cleanup.ok())
|
||||||
|
LOG("Shader::create() vertex shader cleanup failed because: %s", vertex_cleanup.message);
|
||||||
|
if (!fragment_cleanup.ok())
|
||||||
|
LOG("Shader::create() fragment shader cleanup failed because: %s", fragment_cleanup.message);
|
||||||
ret = false;
|
ret = false;
|
||||||
|
LOG("Shader::create() program link failed because: %s", program.status().message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glAttachShader(ps, vs);
|
if (program.value().info_log_length > 0)
|
||||||
glAttachShader(ps, fs);
|
|
||||||
glDeleteShader(vs);
|
|
||||||
glDeleteShader(fs);
|
|
||||||
|
|
||||||
glLinkProgram(ps);
|
|
||||||
for (const auto& binding : pp::renderer::gl::panopainter_shader_attribute_bindings())
|
|
||||||
{
|
|
||||||
if (glGetAttribLocation(ps, binding.name) != -1)
|
|
||||||
glBindAttribLocation(ps, static_cast<GLuint>(binding.location), binding.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
glLinkProgram(ps);
|
|
||||||
glGetProgramiv(ps, program_link_status_query(), &status);
|
|
||||||
glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog);
|
LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog);
|
||||||
if (status == 0)
|
if (program.value().link_status == 0)
|
||||||
{
|
{
|
||||||
glDeleteProgram(ps);
|
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||||
|
program.value().program_id,
|
||||||
|
pp::renderer::gl::OpenGlProgramDeleteDispatch {
|
||||||
|
.use_program = use_opengl_program,
|
||||||
|
.delete_program = delete_opengl_program,
|
||||||
|
});
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("Shader::create() program cleanup failed because: %s", status.message);
|
||||||
ret = false;
|
ret = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto cleanup_program = [](std::uint32_t program_id) noexcept {
|
||||||
|
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||||
|
program_id,
|
||||||
|
pp::renderer::gl::OpenGlProgramDeleteDispatch {
|
||||||
|
.use_program = use_opengl_program,
|
||||||
|
.delete_program = delete_opengl_program,
|
||||||
|
});
|
||||||
|
if (!status.ok())
|
||||||
|
LOG("Shader::create() program cleanup failed because: %s", status.message);
|
||||||
|
};
|
||||||
|
|
||||||
// Parse shader uniforms
|
// Parse shader uniforms
|
||||||
{
|
{
|
||||||
GLint count;
|
const auto uniform_count = pp::renderer::gl::query_opengl_program_integer(
|
||||||
GLint size; // size of the variable
|
program.value().program_id,
|
||||||
GLenum type; // type of the variable (float, vec3 or mat4, etc)
|
pp::renderer::gl::active_uniform_count_query(),
|
||||||
const GLsizei bufSize = 64; // maximum name length
|
pp::renderer::gl::OpenGlProgramIntegerDispatch {
|
||||||
GLchar name[bufSize]; // variable name in GLSL
|
.get_program_integer = query_opengl_program_integer,
|
||||||
GLsizei length; // name length
|
});
|
||||||
glGetProgramiv(ps, active_uniform_count_query(), &count);
|
if (!uniform_count.ok())
|
||||||
|
{
|
||||||
|
LOG("Shader::create() uniform discovery failed because: %s", uniform_count.status().message);
|
||||||
|
cleanup_program(program.value().program_id);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
constexpr std::int32_t bufSize = 64; // maximum name length
|
||||||
|
char uniform_name[bufSize]; // variable name in GLSL
|
||||||
|
const auto count = uniform_count.value();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name);
|
const auto uniform = pp::renderer::gl::get_opengl_active_uniform(
|
||||||
name[length] = 0;
|
program.value().program_id,
|
||||||
kShaderUniform id = static_cast<kShaderUniform>(pp::renderer::gl::shader_uniform_id(name));
|
static_cast<std::uint32_t>(i),
|
||||||
|
uniform_name,
|
||||||
|
bufSize,
|
||||||
|
pp::renderer::gl::OpenGlActiveUniformDispatch {
|
||||||
|
.get_active_uniform = get_opengl_active_uniform,
|
||||||
|
});
|
||||||
|
if (!uniform.ok())
|
||||||
|
{
|
||||||
|
LOG("Shader::create() active uniform discovery failed because: %s", uniform.status().message);
|
||||||
|
cleanup_program(program.value().program_id);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
kShaderUniform id = static_cast<kShaderUniform>(pp::renderer::gl::shader_uniform_id(uniform_name));
|
||||||
if (m_umap.find(id) != m_umap.end())
|
if (m_umap.find(id) != m_umap.end())
|
||||||
LOG("UNIFORM ALREADY DEFINED: %s", name);
|
LOG("UNIFORM ALREADY DEFINED: %s", uniform_name);
|
||||||
m_umap[id] = glGetUniformLocation(ps, name);
|
const auto location = pp::renderer::gl::get_opengl_uniform_location(
|
||||||
//printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name));
|
program.value().program_id,
|
||||||
|
uniform_name,
|
||||||
|
pp::renderer::gl::OpenGlUniformLocationDispatch {
|
||||||
|
.get_uniform_location = get_opengl_uniform_location,
|
||||||
|
});
|
||||||
|
if (!location.ok())
|
||||||
|
{
|
||||||
|
LOG("Shader::create() uniform location failed because: %s", location.status().message);
|
||||||
|
cleanup_program(program.value().program_id);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_umap[id] = location.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prog = ps;
|
prog = program.value().program_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "renderer_gl/shader_bindings.h"
|
#include "renderer_gl/shader_bindings.h"
|
||||||
#include "test_harness.h"
|
#include "test_harness.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -111,6 +112,29 @@ struct RecordedOpenGlUniformScalarCall {
|
|||||||
bool is_float = false;
|
bool is_float = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RecordedOpenGlShaderSourceCall {
|
||||||
|
std::uint32_t shader = 0;
|
||||||
|
std::int32_t count = 0;
|
||||||
|
std::string_view source;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RecordedOpenGlProgramAttachCall {
|
||||||
|
std::uint32_t program = 0;
|
||||||
|
std::uint32_t shader = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RecordedOpenGlAttribBindCall {
|
||||||
|
std::uint32_t program = 0;
|
||||||
|
std::uint32_t location = 0;
|
||||||
|
std::string_view name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RecordedOpenGlActiveUniformCall {
|
||||||
|
std::uint32_t program = 0;
|
||||||
|
std::uint32_t index = 0;
|
||||||
|
std::int32_t capacity = 0;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<RecordedOpenGlStateCall> recorded_state_calls;
|
std::vector<RecordedOpenGlStateCall> recorded_state_calls;
|
||||||
std::vector<std::uint32_t> recorded_string_queries;
|
std::vector<std::uint32_t> recorded_string_queries;
|
||||||
std::vector<pp::renderer::gl::OpenGlDefaultClear> recorded_clear_calls;
|
std::vector<pp::renderer::gl::OpenGlDefaultClear> recorded_clear_calls;
|
||||||
@@ -138,9 +162,27 @@ std::vector<RecordedOpenGlUniformFloatVectorCall> recorded_uniform_vector_calls;
|
|||||||
std::vector<RecordedOpenGlUniformScalarCall> recorded_uniform_scalar_calls;
|
std::vector<RecordedOpenGlUniformScalarCall> recorded_uniform_scalar_calls;
|
||||||
std::vector<std::uint32_t> recorded_attrib_location_programs;
|
std::vector<std::uint32_t> recorded_attrib_location_programs;
|
||||||
std::vector<std::string_view> recorded_attrib_location_names;
|
std::vector<std::string_view> recorded_attrib_location_names;
|
||||||
|
std::vector<std::uint32_t> recorded_created_shader_stages;
|
||||||
|
std::vector<RecordedOpenGlShaderSourceCall> recorded_shader_source_calls;
|
||||||
|
std::vector<std::uint32_t> recorded_compiled_shaders;
|
||||||
|
std::vector<std::uint32_t> recorded_deleted_shaders;
|
||||||
|
std::vector<std::uint32_t> recorded_shader_integer_queries;
|
||||||
|
std::vector<std::uint32_t> recorded_created_programs;
|
||||||
|
std::vector<RecordedOpenGlProgramAttachCall> recorded_program_attach_calls;
|
||||||
|
std::vector<std::uint32_t> recorded_linked_programs;
|
||||||
|
std::vector<RecordedOpenGlAttribBindCall> recorded_attrib_bind_calls;
|
||||||
|
std::vector<std::uint32_t> recorded_program_integer_queries;
|
||||||
|
std::vector<RecordedOpenGlActiveUniformCall> recorded_active_uniform_calls;
|
||||||
|
std::vector<std::uint32_t> recorded_uniform_location_programs;
|
||||||
|
std::vector<std::string_view> recorded_uniform_location_names;
|
||||||
std::uint32_t next_texture_id = 91U;
|
std::uint32_t next_texture_id = 91U;
|
||||||
std::uint32_t next_framebuffer_id = 44U;
|
std::uint32_t next_framebuffer_id = 44U;
|
||||||
std::uint32_t next_sampler_id = 71U;
|
std::uint32_t next_sampler_id = 71U;
|
||||||
|
std::uint32_t next_shader_id = 301U;
|
||||||
|
std::uint32_t next_program_id = 401U;
|
||||||
|
std::int32_t configured_shader_compile_status = 1;
|
||||||
|
std::int32_t configured_program_link_status = 1;
|
||||||
|
std::int32_t configured_active_uniform_count = 2;
|
||||||
std::uint32_t configured_framebuffer_status = 0x8CD5U;
|
std::uint32_t configured_framebuffer_status = 0x8CD5U;
|
||||||
|
|
||||||
void record_enable(std::uint32_t state) noexcept
|
void record_enable(std::uint32_t state) noexcept
|
||||||
@@ -592,6 +634,164 @@ std::int32_t record_get_attrib_location(std::uint32_t program, const char* name)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint32_t record_create_shader(std::uint32_t stage) noexcept
|
||||||
|
{
|
||||||
|
recorded_created_shader_stages.push_back(stage);
|
||||||
|
return next_shader_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_shader_source(std::uint32_t shader, std::int32_t count, const char* const* sources) noexcept
|
||||||
|
{
|
||||||
|
recorded_shader_source_calls.push_back(RecordedOpenGlShaderSourceCall {
|
||||||
|
.shader = shader,
|
||||||
|
.count = count,
|
||||||
|
.source = sources != nullptr && sources[0] != nullptr ? std::string_view { sources[0] } : std::string_view {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_compile_shader(std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
recorded_compiled_shaders.push_back(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_shader_integer(std::uint32_t shader, std::uint32_t query, std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
recorded_shader_integer_queries.push_back(query);
|
||||||
|
if (value != nullptr) {
|
||||||
|
*value = configured_shader_compile_status;
|
||||||
|
}
|
||||||
|
(void)shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_shader_info_log(
|
||||||
|
std::uint32_t shader,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept
|
||||||
|
{
|
||||||
|
constexpr std::string_view log_text { "shader note" };
|
||||||
|
if (length != nullptr) {
|
||||||
|
*length = static_cast<std::int32_t>(log_text.size());
|
||||||
|
}
|
||||||
|
if (info_log != nullptr && capacity > 0) {
|
||||||
|
const auto copied = std::min<std::int32_t>(capacity - 1, static_cast<std::int32_t>(log_text.size()));
|
||||||
|
std::memcpy(info_log, log_text.data(), static_cast<std::size_t>(copied));
|
||||||
|
info_log[copied] = '\0';
|
||||||
|
}
|
||||||
|
(void)shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_delete_shader(std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
recorded_deleted_shaders.push_back(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t record_create_program() noexcept
|
||||||
|
{
|
||||||
|
recorded_created_programs.push_back(next_program_id);
|
||||||
|
return next_program_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_attach_shader(std::uint32_t program, std::uint32_t shader) noexcept
|
||||||
|
{
|
||||||
|
recorded_program_attach_calls.push_back(RecordedOpenGlProgramAttachCall {
|
||||||
|
.program = program,
|
||||||
|
.shader = shader,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_link_program(std::uint32_t program) noexcept
|
||||||
|
{
|
||||||
|
recorded_linked_programs.push_back(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_bind_attrib_location(std::uint32_t program, std::uint32_t location, const char* name) noexcept
|
||||||
|
{
|
||||||
|
recorded_attrib_bind_calls.push_back(RecordedOpenGlAttribBindCall {
|
||||||
|
.program = program,
|
||||||
|
.location = location,
|
||||||
|
.name = name == nullptr ? std::string_view {} : std::string_view { name },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_program_integer(std::uint32_t program, std::uint32_t query, std::int32_t* value) noexcept
|
||||||
|
{
|
||||||
|
recorded_program_integer_queries.push_back(query);
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (query == 0x8B82U) {
|
||||||
|
*value = configured_program_link_status;
|
||||||
|
} else if (query == 0x8B86U) {
|
||||||
|
*value = configured_active_uniform_count;
|
||||||
|
} else {
|
||||||
|
*value = -1;
|
||||||
|
}
|
||||||
|
(void)program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_program_info_log(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
char* info_log) noexcept
|
||||||
|
{
|
||||||
|
constexpr std::string_view log_text { "program note" };
|
||||||
|
if (length != nullptr) {
|
||||||
|
*length = static_cast<std::int32_t>(log_text.size());
|
||||||
|
}
|
||||||
|
if (info_log != nullptr && capacity > 0) {
|
||||||
|
const auto copied = std::min<std::int32_t>(capacity - 1, static_cast<std::int32_t>(log_text.size()));
|
||||||
|
std::memcpy(info_log, log_text.data(), static_cast<std::size_t>(copied));
|
||||||
|
info_log[copied] = '\0';
|
||||||
|
}
|
||||||
|
(void)program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_get_active_uniform(
|
||||||
|
std::uint32_t program,
|
||||||
|
std::uint32_t index,
|
||||||
|
std::int32_t capacity,
|
||||||
|
std::int32_t* length,
|
||||||
|
std::int32_t* size,
|
||||||
|
std::uint32_t* type,
|
||||||
|
char* name) noexcept
|
||||||
|
{
|
||||||
|
recorded_active_uniform_calls.push_back(RecordedOpenGlActiveUniformCall {
|
||||||
|
.program = program,
|
||||||
|
.index = index,
|
||||||
|
.capacity = capacity,
|
||||||
|
});
|
||||||
|
const std::string_view uniform_name = index == 0U ? std::string_view { "mvp" } : std::string_view { "tex" };
|
||||||
|
if (length != nullptr) {
|
||||||
|
*length = static_cast<std::int32_t>(uniform_name.size());
|
||||||
|
}
|
||||||
|
if (size != nullptr) {
|
||||||
|
*size = 1;
|
||||||
|
}
|
||||||
|
if (type != nullptr) {
|
||||||
|
*type = 0x8B5CU;
|
||||||
|
}
|
||||||
|
if (name != nullptr && capacity > 0) {
|
||||||
|
const auto copied = std::min<std::int32_t>(capacity - 1, static_cast<std::int32_t>(uniform_name.size()));
|
||||||
|
std::memcpy(name, uniform_name.data(), static_cast<std::size_t>(copied));
|
||||||
|
name[copied] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t record_get_uniform_location(std::uint32_t program, const char* name) noexcept
|
||||||
|
{
|
||||||
|
recorded_uniform_location_programs.push_back(program);
|
||||||
|
recorded_uniform_location_names.push_back(name == nullptr ? std::string_view {} : std::string_view { name });
|
||||||
|
if (name != nullptr && std::string_view { name } == std::string_view { "mvp" }) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (name != nullptr && std::string_view { name } == std::string_view { "tex" }) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void detects_common_extension_capabilities(pp::tests::Harness& h)
|
void detects_common_extension_capabilities(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
constexpr std::array<std::string_view, 2> extensions {
|
constexpr std::array<std::string_view, 2> extensions {
|
||||||
@@ -2256,6 +2456,321 @@ void rejects_invalid_program_uniform_dispatch(pp::tests::Harness& h)
|
|||||||
PP_EXPECT(h, invalid_attrib_name.status().code == pp::foundation::StatusCode::invalid_argument);
|
PP_EXPECT(h, invalid_attrib_name.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compiles_shader_source_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_created_shader_stages.clear();
|
||||||
|
recorded_shader_source_calls.clear();
|
||||||
|
recorded_compiled_shaders.clear();
|
||||||
|
recorded_shader_integer_queries.clear();
|
||||||
|
next_shader_id = 301U;
|
||||||
|
configured_shader_compile_status = 1;
|
||||||
|
std::array<char, 64> info_log {};
|
||||||
|
|
||||||
|
const auto shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
|
0x8B31U,
|
||||||
|
"void main(){}",
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = record_create_shader,
|
||||||
|
.shader_source = record_shader_source,
|
||||||
|
.compile_shader = record_compile_shader,
|
||||||
|
.get_shader_integer = record_get_shader_integer,
|
||||||
|
.get_shader_info_log = record_get_shader_info_log,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, shader.ok());
|
||||||
|
PP_EXPECT(h, shader.value().shader_id == 301U);
|
||||||
|
PP_EXPECT(h, shader.value().compile_status == 1);
|
||||||
|
PP_EXPECT(h, shader.value().info_log_length == 11);
|
||||||
|
PP_EXPECT(h, std::string_view { info_log.data() } == std::string_view("shader note"));
|
||||||
|
PP_EXPECT(h, recorded_created_shader_stages.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_created_shader_stages[0] == 0x8B31U);
|
||||||
|
PP_EXPECT(h, recorded_shader_source_calls.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_shader_source_calls[0].shader == 301U);
|
||||||
|
PP_EXPECT(h, recorded_shader_source_calls[0].count == 1);
|
||||||
|
PP_EXPECT(h, recorded_shader_source_calls[0].source == std::string_view("void main(){}"));
|
||||||
|
PP_EXPECT(h, recorded_compiled_shaders.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_compiled_shaders[0] == 301U);
|
||||||
|
PP_EXPECT(h, recorded_shader_integer_queries.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_shader_integer_queries[0] == 0x8B81U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_invalid_shader_compile_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::array<char, 16> info_log {};
|
||||||
|
const auto missing_dispatch = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
|
0x8B31U,
|
||||||
|
"void main(){}",
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = record_create_shader,
|
||||||
|
.shader_source = record_shader_source,
|
||||||
|
});
|
||||||
|
const auto empty_source = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
|
0x8B31U,
|
||||||
|
"",
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = record_create_shader,
|
||||||
|
.shader_source = record_shader_source,
|
||||||
|
.compile_shader = record_compile_shader,
|
||||||
|
.get_shader_integer = record_get_shader_integer,
|
||||||
|
.get_shader_info_log = record_get_shader_info_log,
|
||||||
|
});
|
||||||
|
const auto missing_log = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
|
0x8B31U,
|
||||||
|
"void main(){}",
|
||||||
|
nullptr,
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||||
|
.create_shader = record_create_shader,
|
||||||
|
.shader_source = record_shader_source,
|
||||||
|
.compile_shader = record_compile_shader,
|
||||||
|
.get_shader_integer = record_get_shader_integer,
|
||||||
|
.get_shader_info_log = record_get_shader_info_log,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !missing_dispatch.ok());
|
||||||
|
PP_EXPECT(h, missing_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !empty_source.ok());
|
||||||
|
PP_EXPECT(h, empty_source.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !missing_log.ok());
|
||||||
|
PP_EXPECT(h, missing_log.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deletes_shader_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_deleted_shaders.clear();
|
||||||
|
|
||||||
|
const auto delete_status = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
31U,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = record_delete_shader,
|
||||||
|
});
|
||||||
|
const auto delete_zero_status = pp::renderer::gl::delete_opengl_shader(
|
||||||
|
0U,
|
||||||
|
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||||
|
.delete_shader = record_delete_shader,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, delete_status.ok());
|
||||||
|
PP_EXPECT(h, delete_zero_status.ok());
|
||||||
|
PP_EXPECT(h, recorded_deleted_shaders.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_deleted_shaders[0] == 31U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void links_shader_program_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_created_programs.clear();
|
||||||
|
recorded_program_attach_calls.clear();
|
||||||
|
recorded_deleted_shaders.clear();
|
||||||
|
recorded_linked_programs.clear();
|
||||||
|
recorded_attrib_location_programs.clear();
|
||||||
|
recorded_attrib_location_names.clear();
|
||||||
|
recorded_attrib_bind_calls.clear();
|
||||||
|
recorded_program_integer_queries.clear();
|
||||||
|
next_program_id = 401U;
|
||||||
|
configured_program_link_status = 1;
|
||||||
|
std::array<char, 64> info_log {};
|
||||||
|
|
||||||
|
const auto program = pp::renderer::gl::link_opengl_shader_program(
|
||||||
|
101U,
|
||||||
|
103U,
|
||||||
|
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||||
|
.create_program = record_create_program,
|
||||||
|
.attach_shader = record_attach_shader,
|
||||||
|
.delete_shader = record_delete_shader,
|
||||||
|
.link_program = record_link_program,
|
||||||
|
.get_attrib_location = record_get_attrib_location,
|
||||||
|
.bind_attrib_location = record_bind_attrib_location,
|
||||||
|
.get_program_integer = record_get_program_integer,
|
||||||
|
.get_program_info_log = record_get_program_info_log,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, program.ok());
|
||||||
|
PP_EXPECT(h, program.value().program_id == 401U);
|
||||||
|
PP_EXPECT(h, program.value().link_status == 1);
|
||||||
|
PP_EXPECT(h, program.value().info_log_length == 12);
|
||||||
|
PP_EXPECT(h, std::string_view { info_log.data() } == std::string_view("program note"));
|
||||||
|
PP_EXPECT(h, recorded_created_programs.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_created_programs[0] == 401U);
|
||||||
|
PP_EXPECT(h, recorded_program_attach_calls.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_program_attach_calls[0].shader == 101U);
|
||||||
|
PP_EXPECT(h, recorded_program_attach_calls[1].shader == 103U);
|
||||||
|
PP_EXPECT(h, recorded_deleted_shaders.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_deleted_shaders[0] == 101U);
|
||||||
|
PP_EXPECT(h, recorded_deleted_shaders[1] == 103U);
|
||||||
|
PP_EXPECT(h, recorded_linked_programs.size() == 2U);
|
||||||
|
PP_EXPECT(h, recorded_linked_programs[0] == 401U);
|
||||||
|
PP_EXPECT(h, recorded_linked_programs[1] == 401U);
|
||||||
|
PP_EXPECT(h, recorded_attrib_bind_calls.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_attrib_bind_calls[0].program == 401U);
|
||||||
|
PP_EXPECT(h, recorded_attrib_bind_calls[0].location == 1U);
|
||||||
|
PP_EXPECT(h, recorded_attrib_bind_calls[0].name == std::string_view("uvs"));
|
||||||
|
PP_EXPECT(h, recorded_program_integer_queries.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_program_integer_queries[0] == 0x8B82U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_invalid_shader_program_link_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::array<char, 16> info_log {};
|
||||||
|
const auto missing_dispatch = pp::renderer::gl::link_opengl_shader_program(
|
||||||
|
1U,
|
||||||
|
2U,
|
||||||
|
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||||
|
.create_program = record_create_program,
|
||||||
|
.attach_shader = record_attach_shader,
|
||||||
|
});
|
||||||
|
const auto zero_shader = pp::renderer::gl::link_opengl_shader_program(
|
||||||
|
0U,
|
||||||
|
2U,
|
||||||
|
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||||
|
info_log.data(),
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||||
|
.create_program = record_create_program,
|
||||||
|
.attach_shader = record_attach_shader,
|
||||||
|
.delete_shader = record_delete_shader,
|
||||||
|
.link_program = record_link_program,
|
||||||
|
.get_attrib_location = record_get_attrib_location,
|
||||||
|
.bind_attrib_location = record_bind_attrib_location,
|
||||||
|
.get_program_integer = record_get_program_integer,
|
||||||
|
.get_program_info_log = record_get_program_info_log,
|
||||||
|
});
|
||||||
|
const auto missing_log = pp::renderer::gl::link_opengl_shader_program(
|
||||||
|
1U,
|
||||||
|
2U,
|
||||||
|
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||||
|
nullptr,
|
||||||
|
static_cast<std::int32_t>(info_log.size()),
|
||||||
|
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||||
|
.create_program = record_create_program,
|
||||||
|
.attach_shader = record_attach_shader,
|
||||||
|
.delete_shader = record_delete_shader,
|
||||||
|
.link_program = record_link_program,
|
||||||
|
.get_attrib_location = record_get_attrib_location,
|
||||||
|
.bind_attrib_location = record_bind_attrib_location,
|
||||||
|
.get_program_integer = record_get_program_integer,
|
||||||
|
.get_program_info_log = record_get_program_info_log,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !missing_dispatch.ok());
|
||||||
|
PP_EXPECT(h, missing_dispatch.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !zero_shader.ok());
|
||||||
|
PP_EXPECT(h, zero_shader.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !missing_log.ok());
|
||||||
|
PP_EXPECT(h, missing_log.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void discovers_program_uniforms_through_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
recorded_program_integer_queries.clear();
|
||||||
|
recorded_active_uniform_calls.clear();
|
||||||
|
recorded_uniform_location_programs.clear();
|
||||||
|
recorded_uniform_location_names.clear();
|
||||||
|
configured_active_uniform_count = 2;
|
||||||
|
std::array<char, 64> name {};
|
||||||
|
|
||||||
|
const auto count = pp::renderer::gl::query_opengl_program_integer(
|
||||||
|
401U,
|
||||||
|
pp::renderer::gl::active_uniform_count_query(),
|
||||||
|
pp::renderer::gl::OpenGlProgramIntegerDispatch {
|
||||||
|
.get_program_integer = record_get_program_integer,
|
||||||
|
});
|
||||||
|
const auto first = pp::renderer::gl::get_opengl_active_uniform(
|
||||||
|
401U,
|
||||||
|
0U,
|
||||||
|
name.data(),
|
||||||
|
static_cast<std::int32_t>(name.size()),
|
||||||
|
pp::renderer::gl::OpenGlActiveUniformDispatch {
|
||||||
|
.get_active_uniform = record_get_active_uniform,
|
||||||
|
});
|
||||||
|
const auto location = pp::renderer::gl::get_opengl_uniform_location(
|
||||||
|
401U,
|
||||||
|
name.data(),
|
||||||
|
pp::renderer::gl::OpenGlUniformLocationDispatch {
|
||||||
|
.get_uniform_location = record_get_uniform_location,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, count.ok());
|
||||||
|
PP_EXPECT(h, count.value() == 2);
|
||||||
|
PP_EXPECT(h, first.ok());
|
||||||
|
PP_EXPECT(h, first.value().length == 3);
|
||||||
|
PP_EXPECT(h, first.value().size == 1);
|
||||||
|
PP_EXPECT(h, first.value().type == 0x8B5CU);
|
||||||
|
PP_EXPECT(h, std::string_view { name.data() } == std::string_view("mvp"));
|
||||||
|
PP_EXPECT(h, location.ok());
|
||||||
|
PP_EXPECT(h, location.value() == 4);
|
||||||
|
PP_EXPECT(h, recorded_program_integer_queries.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_program_integer_queries[0] == 0x8B86U);
|
||||||
|
PP_EXPECT(h, recorded_active_uniform_calls.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_active_uniform_calls[0].program == 401U);
|
||||||
|
PP_EXPECT(h, recorded_active_uniform_calls[0].index == 0U);
|
||||||
|
PP_EXPECT(h, recorded_uniform_location_names.size() == 1U);
|
||||||
|
PP_EXPECT(h, recorded_uniform_location_names[0] == std::string_view("mvp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rejects_invalid_uniform_discovery_dispatch(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::array<char, 16> name {};
|
||||||
|
const auto missing_program_integer = pp::renderer::gl::query_opengl_program_integer(
|
||||||
|
1U,
|
||||||
|
pp::renderer::gl::active_uniform_count_query(),
|
||||||
|
pp::renderer::gl::OpenGlProgramIntegerDispatch {});
|
||||||
|
const auto invalid_program_integer = pp::renderer::gl::query_opengl_program_integer(
|
||||||
|
0U,
|
||||||
|
pp::renderer::gl::active_uniform_count_query(),
|
||||||
|
pp::renderer::gl::OpenGlProgramIntegerDispatch {
|
||||||
|
.get_program_integer = record_get_program_integer,
|
||||||
|
});
|
||||||
|
const auto missing_active = pp::renderer::gl::get_opengl_active_uniform(
|
||||||
|
1U,
|
||||||
|
0U,
|
||||||
|
name.data(),
|
||||||
|
static_cast<std::int32_t>(name.size()),
|
||||||
|
pp::renderer::gl::OpenGlActiveUniformDispatch {});
|
||||||
|
const auto invalid_active_buffer = pp::renderer::gl::get_opengl_active_uniform(
|
||||||
|
1U,
|
||||||
|
0U,
|
||||||
|
nullptr,
|
||||||
|
static_cast<std::int32_t>(name.size()),
|
||||||
|
pp::renderer::gl::OpenGlActiveUniformDispatch {
|
||||||
|
.get_active_uniform = record_get_active_uniform,
|
||||||
|
});
|
||||||
|
const auto missing_uniform_location = pp::renderer::gl::get_opengl_uniform_location(
|
||||||
|
1U,
|
||||||
|
"mvp",
|
||||||
|
pp::renderer::gl::OpenGlUniformLocationDispatch {});
|
||||||
|
const auto invalid_uniform_name = pp::renderer::gl::get_opengl_uniform_location(
|
||||||
|
1U,
|
||||||
|
"",
|
||||||
|
pp::renderer::gl::OpenGlUniformLocationDispatch {
|
||||||
|
.get_uniform_location = record_get_uniform_location,
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, !missing_program_integer.ok());
|
||||||
|
PP_EXPECT(h, missing_program_integer.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !invalid_program_integer.ok());
|
||||||
|
PP_EXPECT(h, invalid_program_integer.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !missing_active.ok());
|
||||||
|
PP_EXPECT(h, missing_active.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !invalid_active_buffer.ok());
|
||||||
|
PP_EXPECT(h, invalid_active_buffer.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !missing_uniform_location.ok());
|
||||||
|
PP_EXPECT(h, missing_uniform_location.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
PP_EXPECT(h, !invalid_uniform_name.ok());
|
||||||
|
PP_EXPECT(h, invalid_uniform_name.status().code == pp::foundation::StatusCode::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
void updates_texture_2d_through_dispatch(pp::tests::Harness& h)
|
void updates_texture_2d_through_dispatch(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
recorded_binding_calls.clear();
|
recorded_binding_calls.clear();
|
||||||
@@ -3043,6 +3558,13 @@ int main()
|
|||||||
harness.run("sets_scalar_uniforms_through_dispatch", sets_scalar_uniforms_through_dispatch);
|
harness.run("sets_scalar_uniforms_through_dispatch", sets_scalar_uniforms_through_dispatch);
|
||||||
harness.run("queries_attribute_location_through_dispatch", queries_attribute_location_through_dispatch);
|
harness.run("queries_attribute_location_through_dispatch", queries_attribute_location_through_dispatch);
|
||||||
harness.run("rejects_invalid_program_uniform_dispatch", rejects_invalid_program_uniform_dispatch);
|
harness.run("rejects_invalid_program_uniform_dispatch", rejects_invalid_program_uniform_dispatch);
|
||||||
|
harness.run("compiles_shader_source_through_dispatch", compiles_shader_source_through_dispatch);
|
||||||
|
harness.run("rejects_invalid_shader_compile_dispatch", rejects_invalid_shader_compile_dispatch);
|
||||||
|
harness.run("deletes_shader_through_dispatch", deletes_shader_through_dispatch);
|
||||||
|
harness.run("links_shader_program_through_dispatch", links_shader_program_through_dispatch);
|
||||||
|
harness.run("rejects_invalid_shader_program_link_dispatch", rejects_invalid_shader_program_link_dispatch);
|
||||||
|
harness.run("discovers_program_uniforms_through_dispatch", discovers_program_uniforms_through_dispatch);
|
||||||
|
harness.run("rejects_invalid_uniform_discovery_dispatch", rejects_invalid_uniform_discovery_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);
|
||||||
harness.run("generates_texture_2d_mipmaps_through_dispatch", generates_texture_2d_mipmaps_through_dispatch);
|
harness.run("generates_texture_2d_mipmaps_through_dispatch", generates_texture_2d_mipmaps_through_dispatch);
|
||||||
harness.run("reads_back_texture_2d_through_framebuffer_dispatch", reads_back_texture_2d_through_framebuffer_dispatch);
|
harness.run("reads_back_texture_2d_through_framebuffer_dispatch", reads_back_texture_2d_through_framebuffer_dispatch);
|
||||||
|
|||||||
Reference in New Issue
Block a user