mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 13:48:30 +09:00
[Feat] (ProgramState): Implement automatic GLSL uniform management.
- Add SPIRV-Cross/glslang integration for uniform reflection. - Auto-detect and assign locations for uniforms/samplers. - Support most types of uniform. - Implement glUniform* functions with type safety. - Add MG_Util::Program: - GLSL-SPIRV conversion - SPIRV uniform reflection - Program uniform dumping
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#include "DebugTool.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string GLTypeToString(GLenum type) {
|
||||
switch(type) {
|
||||
case GL_FLOAT: return "float";
|
||||
case GL_FLOAT_VEC2: return "vec2";
|
||||
case GL_FLOAT_VEC3: return "vec3";
|
||||
case GL_FLOAT_VEC4: return "vec4";
|
||||
case GL_INT: return "int";
|
||||
case GL_INT_VEC2: return "ivec2";
|
||||
case GL_INT_VEC3: return "ivec3";
|
||||
case GL_INT_VEC4: return "ivec4";
|
||||
case GL_UNSIGNED_INT: return "uint";
|
||||
case GL_UNSIGNED_INT_VEC2: return "uvec2";
|
||||
case GL_UNSIGNED_INT_VEC3: return "uvec3";
|
||||
case GL_UNSIGNED_INT_VEC4: return "uvec4";
|
||||
case GL_BOOL: return "bool";
|
||||
case GL_BOOL_VEC2: return "bvec2";
|
||||
case GL_BOOL_VEC3: return "bvec3";
|
||||
case GL_BOOL_VEC4: return "bvec4";
|
||||
case GL_FLOAT_MAT2: return "mat2";
|
||||
case GL_FLOAT_MAT3: return "mat3";
|
||||
case GL_FLOAT_MAT4: return "mat4";
|
||||
case GL_FLOAT_MAT2x3: return "mat2x3";
|
||||
case GL_FLOAT_MAT2x4: return "mat2x4";
|
||||
case GL_FLOAT_MAT3x2: return "mat3x2";
|
||||
case GL_FLOAT_MAT3x4: return "mat3x4";
|
||||
case GL_FLOAT_MAT4x2: return "mat4x2";
|
||||
case GL_FLOAT_MAT4x3: return "mat4x3";
|
||||
case GL_SAMPLER_1D: return "sampler1D";
|
||||
case GL_SAMPLER_2D: return "sampler2D";
|
||||
case GL_SAMPLER_3D: return "sampler3D";
|
||||
case GL_SAMPLER_CUBE: return "samplerCube";
|
||||
case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
|
||||
case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
|
||||
case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
|
||||
case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
|
||||
case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow";
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow";
|
||||
case GL_SAMPLER_BUFFER: return "samplerBuffer";
|
||||
case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
|
||||
default: return "UnknownType(0x" + std::to_string(type) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
std::string FormatUniformValue(const UniformValue& value) {
|
||||
std::ostringstream ss;
|
||||
ss << "[";
|
||||
|
||||
const size_t elemCount = std::min<size_t>(value.count, 16); // 限制最大显示元素
|
||||
|
||||
switch(value.type) {
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.floatData.size() ? value.floatData[i] : 0.0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.intData.size() ? value.intData[i] : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.uintData.size() ? value.uintData[i] : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_BOOL:
|
||||
case GL_BOOL_VEC2:
|
||||
case GL_BOOL_VEC3:
|
||||
case GL_BOOL_VEC4:
|
||||
for(size_t i=0; i<elemCount; ++i) {
|
||||
if (i > 0) ss << ", ";
|
||||
ss << (i < value.boolData.size() ? (value.boolData[i] ? "true" : "false") : "false");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ss << "N/A";
|
||||
}
|
||||
|
||||
if (value.count > elemCount) ss << ", ...";
|
||||
ss << "]";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void DumpUniforms(const ProgramState& state, GLuint program) {
|
||||
if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
|
||||
return;
|
||||
|
||||
auto prog = (ProgramObject)state.GetProgramObject(program);
|
||||
if (!prog.linked.toBool()) {
|
||||
MG_Util::Debug::LogE("Program %u not linked", program);
|
||||
return;
|
||||
}
|
||||
MG_Util::Debug::LogD("=== Dumping uniforms for program %u ===", program);
|
||||
for(const auto& [name, loc] : prog.uniformLocations) {
|
||||
const auto& value = prog.uniformValues.at(name);
|
||||
MG_Util::Debug::LogD("Uniform: %-24s Location: %-4d Type: %-16s Count: %-3d Value: %s",
|
||||
name.c_str(),
|
||||
loc,
|
||||
GLTypeToString(value.type).c_str(),
|
||||
value.count,
|
||||
FormatUniformValue(value).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void DumpCurrentUniforms(const ProgramState& state) {
|
||||
if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG)
|
||||
return;
|
||||
|
||||
GLuint current = state.GetCurrentProgram();
|
||||
if (current == 0) {
|
||||
MG_Util::Debug::LogE("No active program");
|
||||
return;
|
||||
}
|
||||
DumpUniforms(state, current);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#define MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
#include "../../Includes.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string GLTypeToString(GLenum type);
|
||||
std::string FormatUniformValue(const UniformValue& value);
|
||||
void DumpUniforms(const ProgramState& state, GLuint program);
|
||||
void DumpCurrentUniforms(const ProgramState& state);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_PROGRAM_DEBUGTOOL_H
|
||||
@@ -0,0 +1,405 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#include "GLSLTool.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader) {
|
||||
std::string infoLog;
|
||||
using namespace glslang;
|
||||
|
||||
int glslVersion = QueryGLSLVersion(source);
|
||||
EShLanguage language = GetEShLanguageByShaderType(shaderType);
|
||||
if (language == EShLanguage::EShLangCount) {
|
||||
infoLog += "Error: [Preprocess] Unsupported shader type: " +
|
||||
std::to_string(shaderType);
|
||||
TShader tmpShader(EShLanguage::EShLangVertex);
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
shader = new TShader(language);
|
||||
const char *src = source.c_str();
|
||||
shader->setStrings(&src, 1);
|
||||
shader->setEnvInput(EShSourceGlsl, language, EShClientVulkan, glslVersion);
|
||||
shader->setEnvClient(EShClientOpenGL, EShTargetOpenGL_450);
|
||||
shader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_6);
|
||||
shader->setAutoMapLocations(true);
|
||||
shader->setAutoMapBindings(true);
|
||||
|
||||
// Is InitResources() really correct?
|
||||
TBuiltInResource resources = InitResources();
|
||||
|
||||
if (!shader->parse(&resources, glslVersion, true, EShMsgDefault)) {
|
||||
infoLog += "Error: [glslang] Cannot compile the " + GetShaderTypeName(shaderType) + ":\n"
|
||||
+ std::to_string(shader->getInfoLog());
|
||||
return infoLog;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::vector<unsigned>> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog) {
|
||||
using namespace glslang;
|
||||
|
||||
std::vector<EShLanguage> usedShaderTypes;
|
||||
TProgram program;
|
||||
for (GLuint shaderId : prog.attachedShaders) {
|
||||
auto shaderObject = state.GetShaderObject(shaderId);
|
||||
EShLanguage shLanguage = GetEShLanguageByShaderType(shaderObject.type);
|
||||
TShader* shader = nullptr;
|
||||
std::string infoLogOfShader = CompileGLSLToTShader(shaderObject.type, shaderObject.source, shader);
|
||||
if (!infoLogOfShader.empty()) {
|
||||
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderObject.type) +
|
||||
" :\n" + infoLogOfShader;
|
||||
return {};
|
||||
}
|
||||
program.addShader(shader);
|
||||
usedShaderTypes.push_back(shLanguage);
|
||||
}
|
||||
if (!program.link(EShMsgDefault)) {
|
||||
infoLog = "Error: [glslang] Cannot link the program:\n" + std::to_string(program.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
SpvOptions spvOptions;
|
||||
spvOptions.disableOptimizer = false;
|
||||
|
||||
std::vector<std::vector<unsigned>> allSpirv;
|
||||
for(auto type : usedShaderTypes) {
|
||||
std::vector<unsigned> spirv;
|
||||
GlslangToSpv(*program.getIntermediate(type), spirv, &spvOptions);
|
||||
allSpirv.push_back(spirv);
|
||||
}
|
||||
|
||||
return allSpirv;
|
||||
}
|
||||
|
||||
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string &source, std::string &infoLog) {
|
||||
using namespace glslang;
|
||||
|
||||
TShader* shader = nullptr;
|
||||
std::string infoLogOfShader = CompileGLSLToTShader(shaderType, source, shader);
|
||||
if (!infoLogOfShader.empty()) {
|
||||
infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderType) + ":\n" + infoLogOfShader;
|
||||
return {};
|
||||
}
|
||||
TProgram program;
|
||||
program.addShader(shader);
|
||||
if (!program.link(EShMsgDefault)) {
|
||||
infoLog = "Error: [glslang] Cannot link the program of the single shader:\n" + std::to_string(program.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
std::vector<unsigned> spirv;
|
||||
|
||||
SpvOptions spvOptions;
|
||||
spvOptions.disableOptimizer = false;
|
||||
EShLanguage language = GetEShLanguageByShaderType(shaderType);
|
||||
GlslangToSpv(*program.getIntermediate(language), spirv, &spvOptions);
|
||||
|
||||
return spirv;
|
||||
}
|
||||
|
||||
void ReflectSPIRVUniforms(const std::vector<std::vector<unsigned>>& allSpirv, ProgramObject& prog, std::string& infoLog) {
|
||||
spvc_context context = nullptr;
|
||||
|
||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to create SPIRV-Cross context";
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_set<GLint> used_locations;
|
||||
GLint auto_location = 0;
|
||||
for (auto spirv: allSpirv) {
|
||||
spvc_parsed_ir ir = nullptr;
|
||||
spvc_compiler compiler = nullptr;
|
||||
spvc_resources resources = nullptr;
|
||||
|
||||
spvc_result result = spvc_context_parse_spirv(context, spirv.data(), spirv.size(), &ir);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "SPIR-V parsing failed";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir,
|
||||
SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to create SPIRV-Cross compiler";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
result = spvc_compiler_create_shader_resources(compiler, &resources);
|
||||
if (result != SPVC_SUCCESS) {
|
||||
infoLog = "Failed to get shader resources";
|
||||
spvc_context_destroy(context);
|
||||
return;
|
||||
}
|
||||
|
||||
const spvc_reflected_resource *uniform_buffers = nullptr;
|
||||
const spvc_reflected_resource *uniform_vars = nullptr;
|
||||
const spvc_reflected_resource *sampled_images = nullptr;
|
||||
size_t uniform_buffer_count = 0;
|
||||
size_t uniform_var_count = 0;
|
||||
size_t sampled_image_count = 0;
|
||||
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
|
||||
&uniform_buffers, &uniform_buffer_count);
|
||||
spvc_resources_get_resource_list_for_type(resources,
|
||||
SPVC_RESOURCE_TYPE_GL_PLAIN_UNIFORM,
|
||||
&uniform_vars, &uniform_var_count);
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE,
|
||||
&sampled_images, &sampled_image_count);
|
||||
|
||||
std::vector<const spvc_reflected_resource *> all_resources;
|
||||
for (size_t i = 0; i < uniform_buffer_count; ++i)
|
||||
all_resources.push_back(&uniform_buffers[i]);
|
||||
for (size_t i = 0; i < uniform_var_count; ++i)
|
||||
all_resources.push_back(&uniform_vars[i]);
|
||||
for (size_t i = 0; i < sampled_image_count; ++i)
|
||||
all_resources.push_back(&sampled_images[i]);
|
||||
|
||||
for (const auto res_ptr: all_resources) {
|
||||
const spvc_reflected_resource &res = *res_ptr;
|
||||
const char *name = res.name;
|
||||
if (name[0] == '_') continue;
|
||||
|
||||
unsigned spirv_location = spvc_compiler_get_decoration(compiler, res.id,
|
||||
SpvDecorationLocation);
|
||||
GLint final_location;
|
||||
|
||||
if (spirv_location > 0) {
|
||||
if (used_locations.find(spirv_location) != used_locations.end()) {
|
||||
infoLog += "\nLocation conflict for uniform: " + std::string(name);
|
||||
continue;
|
||||
}
|
||||
final_location = spirv_location;
|
||||
} else {
|
||||
while (used_locations.find(auto_location) != used_locations.end()) {
|
||||
auto_location++;
|
||||
}
|
||||
final_location = auto_location;
|
||||
}
|
||||
|
||||
used_locations.insert(final_location);
|
||||
|
||||
spvc_type_id type_id = res.type_id;
|
||||
spvc_type type = spvc_compiler_get_type_handle(compiler, type_id);
|
||||
spvc_basetype base_type = spvc_type_get_basetype(type);
|
||||
GLenum gl_type = GL_NONE;
|
||||
|
||||
if (base_type == SPVC_BASETYPE_SAMPLED_IMAGE) {
|
||||
SpvDim dim = spvc_type_get_image_dimension(type);
|
||||
bool is_array = spvc_type_get_image_arrayed(type);
|
||||
bool is_shadow = spvc_type_get_image_is_depth(type);
|
||||
bool is_ms = spvc_type_get_image_multisampled(type);
|
||||
|
||||
switch (dim) {
|
||||
case SpvDim1D:
|
||||
gl_type = is_array ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_1D_ARRAY_SHADOW
|
||||
: GL_SAMPLER_1D_SHADOW;
|
||||
break;
|
||||
case SpvDim2D:
|
||||
if (is_ms) {
|
||||
gl_type = is_array ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY
|
||||
: GL_SAMPLER_2D_MULTISAMPLE;
|
||||
} else {
|
||||
gl_type = is_array ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_2D_ARRAY_SHADOW
|
||||
: GL_SAMPLER_2D_SHADOW;
|
||||
}
|
||||
break;
|
||||
case SpvDim3D:
|
||||
gl_type = GL_SAMPLER_3D;
|
||||
break;
|
||||
case SpvDimCube:
|
||||
gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
|
||||
if (is_shadow)
|
||||
gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW
|
||||
: GL_SAMPLER_CUBE_SHADOW;
|
||||
break;
|
||||
case SpvDimRect:
|
||||
gl_type = is_shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case SpvDimBuffer:
|
||||
gl_type = GL_SAMPLER_BUFFER;
|
||||
break;
|
||||
default:
|
||||
gl_type = GL_SAMPLER_2D;
|
||||
}
|
||||
|
||||
spvc_basetype sampled_base = spvc_type_get_basetype(type);
|
||||
if (sampled_base == SPVC_BASETYPE_INT32) {
|
||||
switch (gl_type) {
|
||||
case GL_SAMPLER_1D:
|
||||
gl_type = GL_INT_SAMPLER_1D;
|
||||
break;
|
||||
case GL_SAMPLER_2D:
|
||||
gl_type = GL_INT_SAMPLER_2D;
|
||||
break;
|
||||
case GL_SAMPLER_3D:
|
||||
gl_type = GL_INT_SAMPLER_3D;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE:
|
||||
gl_type = GL_INT_SAMPLER_CUBE;
|
||||
break;
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_1D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_CUBE_MAP_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
gl_type = GL_INT_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case GL_SAMPLER_BUFFER:
|
||||
gl_type = GL_INT_SAMPLER_BUFFER;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
|
||||
break;
|
||||
}
|
||||
} else if (sampled_base == SPVC_BASETYPE_UINT32) {
|
||||
switch (gl_type) {
|
||||
case GL_SAMPLER_1D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_1D;
|
||||
break;
|
||||
case GL_SAMPLER_2D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D;
|
||||
break;
|
||||
case GL_SAMPLER_3D:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_3D;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE;
|
||||
break;
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_1D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_RECT;
|
||||
break;
|
||||
case GL_SAMPLER_BUFFER:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_BUFFER;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
break;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned vec_size = spvc_type_get_vector_size(type);
|
||||
unsigned columns = spvc_type_get_columns(type);
|
||||
|
||||
switch (base_type) {
|
||||
case SPVC_BASETYPE_FP32:
|
||||
if (columns > 1) {
|
||||
if (vec_size == 2 && columns == 2) gl_type = GL_FLOAT_MAT2;
|
||||
else if (vec_size == 3 && columns == 3) gl_type = GL_FLOAT_MAT3;
|
||||
else if (vec_size == 4 && columns == 4) gl_type = GL_FLOAT_MAT4;
|
||||
else if (vec_size == 3 && columns == 2) gl_type = GL_FLOAT_MAT2x3;
|
||||
else if (vec_size == 4 && columns == 2) gl_type = GL_FLOAT_MAT2x4;
|
||||
else if (vec_size == 2 && columns == 3) gl_type = GL_FLOAT_MAT3x2;
|
||||
else if (vec_size == 4 && columns == 3) gl_type = GL_FLOAT_MAT3x4;
|
||||
else if (vec_size == 2 && columns == 4) gl_type = GL_FLOAT_MAT4x2;
|
||||
else if (vec_size == 3 && columns == 4) gl_type = GL_FLOAT_MAT4x3;
|
||||
} else {
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_FLOAT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_FLOAT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_FLOAT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_FLOAT_VEC4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_INT32:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_INT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_INT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_INT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_INT_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_UINT32:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_UNSIGNED_INT;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_UNSIGNED_INT_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_UNSIGNED_INT_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_UNSIGNED_INT_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SPVC_BASETYPE_BOOLEAN:
|
||||
switch (vec_size) {
|
||||
case 1:
|
||||
gl_type = GL_BOOL;
|
||||
break;
|
||||
case 2:
|
||||
gl_type = GL_BOOL_VEC2;
|
||||
break;
|
||||
case 3:
|
||||
gl_type = GL_BOOL_VEC3;
|
||||
break;
|
||||
case 4:
|
||||
gl_type = GL_BOOL_VEC4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
prog.uniformLocations[name] = final_location;
|
||||
UniformValue uniformValue;
|
||||
uniformValue.type = gl_type;
|
||||
uniformValue.count = spvc_type_get_array_dimension(type, 0) > 0 ?
|
||||
spvc_type_get_array_dimension(type, 0) : 1;
|
||||
prog.uniformValues[name] = uniformValue;
|
||||
}
|
||||
}
|
||||
spvc_context_destroy(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_GLSLTOOL_H
|
||||
#define MOBILEGL_GLSLTOOL_H
|
||||
|
||||
#include "../../Includes.h"
|
||||
|
||||
namespace MG_Util::Program {
|
||||
inline static TBuiltInResource InitResources()
|
||||
{
|
||||
TBuiltInResource Resources{};
|
||||
Resources.maxLights = 32;
|
||||
Resources.maxClipPlanes = 6;
|
||||
Resources.maxTextureUnits = 32;
|
||||
Resources.maxTextureCoords = 32;
|
||||
Resources.maxVertexAttribs = 64;
|
||||
Resources.maxVertexUniformComponents = 4096;
|
||||
Resources.maxVaryingFloats = 64;
|
||||
Resources.maxVertexTextureImageUnits = 32;
|
||||
Resources.maxCombinedTextureImageUnits = 80;
|
||||
Resources.maxTextureImageUnits = 32;
|
||||
Resources.maxFragmentUniformComponents = 4096;
|
||||
Resources.maxDrawBuffers = 32;
|
||||
Resources.maxVertexUniformVectors = 128;
|
||||
Resources.maxVaryingVectors = 8;
|
||||
Resources.maxFragmentUniformVectors = 16;
|
||||
Resources.maxVertexOutputVectors = 16;
|
||||
Resources.maxFragmentInputVectors = 15;
|
||||
Resources.minProgramTexelOffset = -8;
|
||||
Resources.maxProgramTexelOffset = 7;
|
||||
Resources.maxClipDistances = 8;
|
||||
Resources.maxComputeWorkGroupCountX = 65535;
|
||||
Resources.maxComputeWorkGroupCountY = 65535;
|
||||
Resources.maxComputeWorkGroupCountZ = 65535;
|
||||
Resources.maxComputeWorkGroupSizeX = 1024;
|
||||
Resources.maxComputeWorkGroupSizeY = 1024;
|
||||
Resources.maxComputeWorkGroupSizeZ = 64;
|
||||
Resources.maxComputeUniformComponents = 1024;
|
||||
Resources.maxComputeTextureImageUnits = 16;
|
||||
Resources.maxComputeImageUniforms = 8;
|
||||
Resources.maxComputeAtomicCounters = 8;
|
||||
Resources.maxComputeAtomicCounterBuffers = 1;
|
||||
Resources.maxVaryingComponents = 60;
|
||||
Resources.maxVertexOutputComponents = 64;
|
||||
Resources.maxGeometryInputComponents = 64;
|
||||
Resources.maxGeometryOutputComponents = 128;
|
||||
Resources.maxFragmentInputComponents = 128;
|
||||
Resources.maxImageUnits = 8;
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs = 8;
|
||||
Resources.maxCombinedShaderOutputResources = 8;
|
||||
Resources.maxImageSamples = 0;
|
||||
Resources.maxVertexImageUniforms = 0;
|
||||
Resources.maxTessControlImageUniforms = 0;
|
||||
Resources.maxTessEvaluationImageUniforms = 0;
|
||||
Resources.maxGeometryImageUniforms = 0;
|
||||
Resources.maxFragmentImageUniforms = 8;
|
||||
Resources.maxCombinedImageUniforms = 8;
|
||||
Resources.maxGeometryTextureImageUnits = 16;
|
||||
Resources.maxGeometryOutputVertices = 256;
|
||||
Resources.maxGeometryTotalOutputComponents = 1024;
|
||||
Resources.maxGeometryUniformComponents = 1024;
|
||||
Resources.maxGeometryVaryingComponents = 64;
|
||||
Resources.maxTessControlInputComponents = 128;
|
||||
Resources.maxTessControlOutputComponents = 128;
|
||||
Resources.maxTessControlTextureImageUnits = 16;
|
||||
Resources.maxTessControlUniformComponents = 1024;
|
||||
Resources.maxTessControlTotalOutputComponents = 4096;
|
||||
Resources.maxTessEvaluationInputComponents = 128;
|
||||
Resources.maxTessEvaluationOutputComponents = 128;
|
||||
Resources.maxTessEvaluationTextureImageUnits = 16;
|
||||
Resources.maxTessEvaluationUniformComponents = 1024;
|
||||
Resources.maxTessPatchComponents = 120;
|
||||
Resources.maxPatchVertices = 32;
|
||||
Resources.maxTessGenLevel = 64;
|
||||
Resources.maxViewports = 16;
|
||||
Resources.maxVertexAtomicCounters = 0;
|
||||
Resources.maxTessControlAtomicCounters = 0;
|
||||
Resources.maxTessEvaluationAtomicCounters = 0;
|
||||
Resources.maxGeometryAtomicCounters = 0;
|
||||
Resources.maxFragmentAtomicCounters = 8;
|
||||
Resources.maxCombinedAtomicCounters = 8;
|
||||
Resources.maxAtomicCounterBindings = 1;
|
||||
Resources.maxVertexAtomicCounterBuffers = 0;
|
||||
Resources.maxTessControlAtomicCounterBuffers = 0;
|
||||
Resources.maxTessEvaluationAtomicCounterBuffers = 0;
|
||||
Resources.maxGeometryAtomicCounterBuffers = 0;
|
||||
Resources.maxFragmentAtomicCounterBuffers = 1;
|
||||
Resources.maxCombinedAtomicCounterBuffers = 1;
|
||||
Resources.maxAtomicCounterBufferSize = 16384;
|
||||
Resources.maxTransformFeedbackBuffers = 4;
|
||||
Resources.maxTransformFeedbackInterleavedComponents = 64;
|
||||
Resources.maxCullDistances = 8;
|
||||
Resources.maxCombinedClipAndCullDistances = 8;
|
||||
Resources.maxSamples = 4;
|
||||
Resources.maxMeshOutputVerticesNV = 256;
|
||||
Resources.maxMeshOutputPrimitivesNV = 512;
|
||||
Resources.maxMeshWorkGroupSizeX_NV = 32;
|
||||
Resources.maxMeshWorkGroupSizeY_NV = 1;
|
||||
Resources.maxMeshWorkGroupSizeZ_NV = 1;
|
||||
Resources.maxTaskWorkGroupSizeX_NV = 32;
|
||||
Resources.maxTaskWorkGroupSizeY_NV = 1;
|
||||
Resources.maxTaskWorkGroupSizeZ_NV = 1;
|
||||
Resources.maxMeshViewCountNV = 4;
|
||||
|
||||
Resources.limits.nonInductiveForLoops = true;
|
||||
Resources.limits.whileLoops = true;
|
||||
Resources.limits.doWhileLoops = true;
|
||||
Resources.limits.generalUniformIndexing = true;
|
||||
Resources.limits.generalAttributeMatrixVectorIndexing = true;
|
||||
Resources.limits.generalVaryingIndexing = true;
|
||||
Resources.limits.generalSamplerIndexing = true;
|
||||
Resources.limits.generalVariableIndexing = true;
|
||||
Resources.limits.generalConstantMatrixVectorIndexing = true;
|
||||
|
||||
return Resources;
|
||||
}
|
||||
|
||||
inline int QueryGLSLVersion(const std::string& code) {
|
||||
static std::regex version_pattern(R"(#version\s+(\d{3}))");
|
||||
std::smatch match;
|
||||
if (std::regex_search(code, match, version_pattern)) {
|
||||
return std::stoi(match[1].str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline GLsizei GetMatrixElementCount(GLenum matrixType) {
|
||||
switch(matrixType) {
|
||||
case GL_FLOAT_MAT2: return 4;
|
||||
case GL_FLOAT_MAT3: return 9;
|
||||
case GL_FLOAT_MAT4: return 16;
|
||||
case GL_FLOAT_MAT2x3: return 6;
|
||||
case GL_FLOAT_MAT2x4: return 8;
|
||||
case GL_FLOAT_MAT3x2: return 6;
|
||||
case GL_FLOAT_MAT3x4: return 12;
|
||||
case GL_FLOAT_MAT4x2: return 8;
|
||||
case GL_FLOAT_MAT4x3: return 12;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string GetShaderTypeName(GLenum shaderType) {
|
||||
switch(shaderType) {
|
||||
case GL_VERTEX_SHADER: return "Vertex Shader";
|
||||
case GL_FRAGMENT_SHADER: return "Fragment Shader";
|
||||
case GL_GEOMETRY_SHADER: return "Geometry Shader";
|
||||
case GL_TESS_CONTROL_SHADER: return "Tessellation Control Shader";
|
||||
case GL_TESS_EVALUATION_SHADER: return "Tessellation Evaluation Shader";
|
||||
case GL_COMPUTE_SHADER: return "Compute Shader";
|
||||
default: return "Unknown Shader Type (" + std::to_string(shaderType) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
inline EShLanguage GetEShLanguageByShaderType(GLenum shaderType) {
|
||||
switch (shaderType) {
|
||||
case GL_VERTEX_SHADER:
|
||||
return EShLanguage::EShLangVertex;
|
||||
case GL_FRAGMENT_SHADER:
|
||||
return EShLanguage::EShLangFragment;
|
||||
case GL_COMPUTE_SHADER:
|
||||
return EShLanguage::EShLangCompute;
|
||||
case GL_TESS_CONTROL_SHADER:
|
||||
return EShLanguage::EShLangTessControl;
|
||||
case GL_TESS_EVALUATION_SHADER:
|
||||
return EShLanguage::EShLangTessEvaluation;
|
||||
case GL_GEOMETRY_SHADER:
|
||||
return EShLanguage::EShLangGeometry;
|
||||
default:
|
||||
return EShLanguage::EShLangCount;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned> CompileGLSLToSPIRV(GLenum shaderType, const std::string& source, std::string& infoLog);
|
||||
std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader);
|
||||
std::vector<std::vector<unsigned>> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog);
|
||||
void ReflectSPIRVUniforms(const std::vector<std::vector<unsigned>>& allSpirv, ProgramObject& prog, std::string& infoLog);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GLSLTOOL_H
|
||||
Reference in New Issue
Block a user