mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (GL_Drawing): Add DrawElementsSHITTILY. Add SPIRV->GLSL ES conversion.
This commit is contained in:
+1
-1
@@ -27,7 +27,7 @@ namespace MG_Global {
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
inline const int LogLevel = MG_Constants::Common::LOG_LEVEL_DEBUG;
|
||||
inline const int LogLevel = MG_Constants::Common::LOG_LEVEL_INFO;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
inline const char* LOG_FILE_PATH = "/sdcard/MG/latest.log";
|
||||
|
||||
@@ -43,14 +43,6 @@ namespace MG_GL::GL {
|
||||
MG_Util::Debug::LogE("Error setting separate blend func: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void Clear(GLbitfield mask) {
|
||||
MG_Util::Debug::LogD("glClear, mask: 0x%X", mask);
|
||||
GLenum result = MG_State::glClear(mask);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
MG_Util::Debug::LogD("glClearColor, rgba: [%.2f, %.2f, %.2f, %.2f]", red, green, blue, alpha);
|
||||
GLenum result = MG_State::glClearColor(red, green, blue, alpha);
|
||||
|
||||
@@ -4,14 +4,850 @@
|
||||
|
||||
#include "GL_Drawing.h"
|
||||
|
||||
#undef MOBILEGL_GLSLTOOL_H
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
// This is a test function that directly draws textures.
|
||||
std::string processOutColorLocations(const std::string& glslCode) {
|
||||
const static std::regex pattern(R"(\n(out highp vec4 outColor)(\d+);)");
|
||||
const std::string replacement = "\nlayout(location=$2) $1$2;";
|
||||
return std::regex_replace(glslCode, pattern, replacement);
|
||||
}
|
||||
|
||||
std::string forceSupporterOutput(const std::string& glslCode) {
|
||||
bool hasPrecisionFloat = glslCode.find("precision ") != std::string::npos &&
|
||||
glslCode.find("float;") != std::string::npos;
|
||||
bool hasPrecisionInt = glslCode.find("precision ") != std::string::npos &&
|
||||
glslCode.find("int;") != std::string::npos;
|
||||
|
||||
std::string result = glslCode;
|
||||
std::string precisionFloat;
|
||||
std::string precisionInt;
|
||||
|
||||
if (hasPrecisionFloat && hasPrecisionInt) {
|
||||
std::istringstream iss(result);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
bool isPrecisionLine = (line.find("precision ") != std::string::npos) &&
|
||||
(line.find("float;") != std::string::npos || line.find("int;") != std::string::npos);
|
||||
if (!isPrecisionLine) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
result.clear();
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
if (i != 0) result += '\n';
|
||||
result += lines[i];
|
||||
}
|
||||
precisionFloat = "precision highp float;\n";
|
||||
precisionInt = "precision highp int;\n";
|
||||
} else {
|
||||
precisionFloat = hasPrecisionFloat ? "" : "precision highp float;\n";
|
||||
precisionInt = hasPrecisionInt ? "" : "precision highp int;\n";
|
||||
}
|
||||
|
||||
size_t lastExtensionPos = result.rfind("#extension");
|
||||
size_t insertionPos = 0;
|
||||
|
||||
if (lastExtensionPos != std::string::npos) {
|
||||
size_t nextNewline = result.find('\n', lastExtensionPos);
|
||||
if (nextNewline != std::string::npos) {
|
||||
insertionPos = nextNewline + 1;
|
||||
} else {
|
||||
insertionPos = result.length();
|
||||
}
|
||||
} else {
|
||||
size_t firstNewline = result.find('\n');
|
||||
if (firstNewline != std::string::npos) {
|
||||
insertionPos = firstNewline + 1;
|
||||
} else {
|
||||
result = precisionFloat + precisionInt + result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result.insert(insertionPos, precisionFloat + precisionInt);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string removeLayoutBinding(const std::string& glslCode) {
|
||||
static std::regex bindingRegex(R"(layout\s*\(\s*binding\s*=\s*\d+\s*\)\s*)");
|
||||
std::string result = std::regex_replace(glslCode, bindingRegex, "");
|
||||
static std::regex bindingRegex2(R"(layout\s*\(\s*binding\s*=\s*\d+\s*,)");
|
||||
result = std::regex_replace(result, bindingRegex2, "layout(");
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::unordered_map<GLuint, GLuint> s_textureMap;
|
||||
static std::unordered_map<GLuint, GLuint> s_vaoMap;
|
||||
static std::unordered_map<GLuint, GLuint> s_bufferMap;
|
||||
static std::unordered_map<GLuint, GLuint> s_programMap;
|
||||
static std::unordered_map<GLuint, GLuint> s_framebufferMap;
|
||||
struct MipLevelInfo {
|
||||
GLenum internalFormat;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
};
|
||||
|
||||
void CheckGLESError() {
|
||||
while (GLenum err = ::GLES::glGetError() != GL_NO_ERROR) {
|
||||
MG_Util::Debug::LogE("-> GLES Error: %s", MG_Util::Debug::GLEnumToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
#define CallAndCheck(operation) MG_Util::Debug::LogD("GLES call: %s", #operation); operation CheckGLESError();
|
||||
static std::unordered_map<GLuint, std::unordered_map<GLint, bool>> s_textureLevelUploaded;
|
||||
|
||||
void SyncAllTexturesToGLES(TextureState* textureState) {
|
||||
MG_Util::Debug::LogD("Syncing all textures to GLES...");
|
||||
for (auto& [mgTexId, texObj] : textureState->textures) {
|
||||
if (!texObj.generated) continue;
|
||||
|
||||
if (s_textureMap.find(mgTexId) == s_textureMap.end()) {
|
||||
GLuint glTexId;
|
||||
CallAndCheck(::GLES::glGenTextures(1, &glTexId);)
|
||||
s_textureMap[mgTexId] = glTexId;
|
||||
GLenum target = texObj.target;
|
||||
CallAndCheck(::GLES::glBindTexture(target, glTexId);)
|
||||
|
||||
for (auto& [pname, param] : texObj.params.texPropertiesInt) {
|
||||
CallAndCheck(::GLES::glTexParameteri(target, pname, param);)
|
||||
}
|
||||
for (auto& [pname, param] : texObj.params.texPropertiesFloat) {
|
||||
CallAndCheck(::GLES::glTexParameterf(target, pname, param);)
|
||||
}
|
||||
|
||||
for (auto& [level, mip] : texObj.params.mipmapData) {
|
||||
const void* data = !mip.pixelData.empty() ? mip.pixelData.data() : nullptr;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
CallAndCheck(::GLES::glTexImage2D(
|
||||
target, level, mip.internalFormat,
|
||||
mip.width, mip.height, 0,
|
||||
mip.format, mip.type, data
|
||||
);)
|
||||
s_textureLevelUploaded[mgTexId][level] = true;
|
||||
MG_Util::Debug::LogD("Initial upload texture %u level %d (size=%zu)", mgTexId, level, mip.pixelData.size());
|
||||
break;
|
||||
default:
|
||||
MG_Util::Debug::LogE("Unsupported target: %s", MG_Util::Debug::GLEnumToString(target));
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("Created and synced new GLES texture %u (MobileGL ID)", mgTexId);
|
||||
} else {
|
||||
GLuint glTexId = s_textureMap[mgTexId];
|
||||
GLenum target = texObj.target;
|
||||
CallAndCheck(::GLES::glBindTexture(target, glTexId);)
|
||||
|
||||
for (auto& [level, mip] : texObj.params.mipmapData) {
|
||||
if (!s_textureLevelUploaded[mgTexId][level]) {
|
||||
bool levelInitialized = s_textureLevelUploaded[mgTexId].count(level);
|
||||
const void* data = !mip.pixelData.empty() ? mip.pixelData.data() : nullptr;
|
||||
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
if (levelInitialized) {
|
||||
CallAndCheck(::GLES::glTexSubImage2D(
|
||||
target, level,
|
||||
0, 0,
|
||||
mip.width, mip.height,
|
||||
mip.format, mip.type, data
|
||||
);)
|
||||
s_textureLevelUploaded[mgTexId][level] = true;
|
||||
MG_Util::Debug::LogD("Updated texture %u level %d with glTexSubImage2D", mgTexId, level);
|
||||
} else {
|
||||
CallAndCheck(::GLES::glTexImage2D(
|
||||
target, level, mip.internalFormat,
|
||||
mip.width, mip.height, 0,
|
||||
mip.format, mip.type, data
|
||||
);)
|
||||
s_textureLevelUploaded[mgTexId][level] = true;
|
||||
MG_Util::Debug::LogD("Initialized texture %u level %d with glTexImage2D", mgTexId, level);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MG_Util::Debug::LogE("Unsupported target: %s", MG_Util::Debug::GLEnumToString(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
MG_Util::Debug::LogD("Updated existing GLES texture %u (MobileGL ID)", mgTexId);
|
||||
}
|
||||
}
|
||||
CallAndCheck(::GLES::glBindTexture(GL_TEXTURE_2D, 0);)
|
||||
}
|
||||
|
||||
|
||||
static std::unordered_map<GLuint, void*> s_bufferDirtyFlags_bufferObj;
|
||||
void SyncAllBuffersToGLES(BufferState* bufferState) {
|
||||
GLint currentVBO = 0, currentEBO = 0;
|
||||
CallAndCheck(::GLES::glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤tVBO);)
|
||||
CallAndCheck(::GLES::glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤tEBO);)
|
||||
for (auto& [mgBufferId, bufferObj] : bufferState->buffers_) {
|
||||
if (!bufferObj.generated) continue;
|
||||
|
||||
// TODO: Check if the buffer changes rather than always update it.
|
||||
if (s_bufferMap.find(mgBufferId) == s_bufferMap.end() || true) {
|
||||
if (s_bufferMap.find(mgBufferId) == s_bufferMap.end()) {
|
||||
GLuint glBuffer;
|
||||
CallAndCheck(::GLES::glGenBuffers(1, &glBuffer);)
|
||||
s_bufferMap[mgBufferId] = glBuffer;
|
||||
}
|
||||
CallAndCheck(::GLES::glBindBuffer(bufferObj.target, s_bufferMap[mgBufferId]);)
|
||||
CallAndCheck(::GLES::glBufferData(
|
||||
bufferObj.target,
|
||||
bufferObj.data.size(),
|
||||
bufferObj.data.data(),
|
||||
bufferObj.usage
|
||||
);)
|
||||
s_bufferDirtyFlags_bufferObj[mgBufferId] = bufferObj.data.data();
|
||||
}
|
||||
}
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ARRAY_BUFFER, currentVBO);)
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, currentEBO);)
|
||||
}
|
||||
|
||||
void DrawArraysSHITTILY(GLenum mode, GLint first, GLsizei count) {
|
||||
|
||||
}
|
||||
|
||||
static GLuint lastBoundVAO = 0;
|
||||
static GLuint lastBoundProgram = 0;
|
||||
static GLuint lastBoundFBO = 0;
|
||||
static std::array<GLuint, 32> lastBoundTextures;
|
||||
void DrawElementsSHITTILY(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
|
||||
CommonState* commonState = MG_State_T::commonState;
|
||||
TextureState* textureState = MG_State_T::textureState;
|
||||
BufferState* bufferState = MG_State_T::bufferState;
|
||||
VertexArrayState* vaState = MG_State_T::vertexArrayState;
|
||||
ProgramState* programState = MG_State_T::programState;
|
||||
FramebufferState* fbState = MG_State_T::framebufferState;
|
||||
|
||||
// Common
|
||||
const GLint* viewport = commonState->viewport;
|
||||
if (viewport[2] > 0 && viewport[3] > 0) {
|
||||
CallAndCheck(::GLES::glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_BLEND]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_BLEND);)
|
||||
CallAndCheck(::GLES::glBlendFuncSeparate(
|
||||
commonState->blendSrcRGB, commonState->blendDstRGB,
|
||||
commonState->blendSrcAlpha, commonState->blendDstAlpha
|
||||
);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_BLEND);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_DEPTH_TEST]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_DEPTH_TEST);)
|
||||
CallAndCheck(::GLES::glDepthMask(commonState->depthMask);)
|
||||
CallAndCheck(::GLES::glDepthFunc(commonState->depthFunc);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_DEPTH_TEST);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_CULL_FACE]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_CULL_FACE);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_CULL_FACE);)
|
||||
}
|
||||
|
||||
CallAndCheck(::GLES::glColorMask(
|
||||
commonState->colorMask[0], commonState->colorMask[1],
|
||||
commonState->colorMask[2], commonState->colorMask[3]
|
||||
);)
|
||||
|
||||
// Texture
|
||||
SyncAllTexturesToGLES(textureState);
|
||||
for (size_t unitIdx = 0; unitIdx < textureState->textureUnits_.size(); ++unitIdx) {
|
||||
TextureUnitState& mgUnit = textureState->textureUnits_[unitIdx];
|
||||
GLenum glUnit = GL_TEXTURE0 + unitIdx;
|
||||
|
||||
if (lastBoundTextures[unitIdx] != mgUnit.boundTextures[GL_TEXTURE_2D]) {
|
||||
CallAndCheck(::GLES::glActiveTexture(glUnit);)
|
||||
for (auto& [target, texId] : mgUnit.boundTextures) {
|
||||
if (texId == 0) {
|
||||
CallAndCheck(::GLES::glBindTexture(target, 0);)
|
||||
lastBoundTextures[unitIdx] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s_textureMap.find(texId) == s_textureMap.end()) {
|
||||
GLuint glTexId;
|
||||
CallAndCheck(::GLES::glGenTextures(1, &glTexId);)
|
||||
s_textureMap[texId] = glTexId;
|
||||
|
||||
CallAndCheck(::GLES::glBindTexture(target, glTexId);)
|
||||
TextureObject& mgTex = textureState->textures[texId];
|
||||
|
||||
for (auto& [pname, param] : mgTex.params.texPropertiesInt) {
|
||||
CallAndCheck(::GLES::glTexParameteri(target, pname, param);)
|
||||
}
|
||||
for (auto& [pname, param] : mgTex.params.texPropertiesFloat) {
|
||||
CallAndCheck(::GLES::glTexParameterf(target, pname, param);)
|
||||
}
|
||||
|
||||
for (auto& [level, mip] : mgTex.params.mipmapData) {
|
||||
CallAndCheck(::GLES::glTexImage2D(
|
||||
target, level, mip.internalFormat,
|
||||
mip.width, mip.height, 0,
|
||||
mip.format, mip.type, mip.pixelData.data()
|
||||
);)
|
||||
}
|
||||
}
|
||||
CallAndCheck(::GLES::glBindTexture(target, s_textureMap[texId]);)
|
||||
lastBoundTextures[unitIdx] = s_textureMap[texId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer
|
||||
SyncAllBuffersToGLES(bufferState);
|
||||
|
||||
// VAO
|
||||
GLuint mgVAO = vaState->currentVao_;
|
||||
VertexArrayObject* vao = &vaState->vaos_[vaState->currentVao_];
|
||||
for (auto& [mgVAOId, mgVAO] : vaState->vaos_) {
|
||||
if (!mgVAO.generated) continue;
|
||||
|
||||
// TODO: Check is the VAO changes rather than always update it.
|
||||
//if (!s_vaoMap.count(mgVAOId)) {
|
||||
GLuint glVAO;
|
||||
if (!s_vaoMap.count(mgVAOId)) {
|
||||
CallAndCheck(::GLES::glGenVertexArrays(1, &glVAO);)
|
||||
s_vaoMap[mgVAOId] = glVAO;
|
||||
|
||||
} else {
|
||||
glVAO = s_vaoMap[mgVAOId];
|
||||
}
|
||||
CallAndCheck(::GLES::glBindVertexArray(glVAO);)
|
||||
|
||||
if (mgVAO.elementBuffer != 0 && s_bufferMap.count(mgVAO.elementBuffer)) {
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_bufferMap[mgVAO.elementBuffer]);)
|
||||
}
|
||||
|
||||
for (auto& [index, attrib] : mgVAO.attribs) {
|
||||
if (attrib.buffer != 0 && s_bufferMap.count(attrib.buffer)) {
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ARRAY_BUFFER, s_bufferMap[attrib.buffer]);)
|
||||
|
||||
if (attrib.isInteger) {
|
||||
CallAndCheck(::GLES::glVertexAttribIPointer(
|
||||
index, attrib.size, attrib.type,
|
||||
attrib.stride, attrib.pointer
|
||||
);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glVertexAttribPointer(
|
||||
index, attrib.size, attrib.type,
|
||||
attrib.normalized ? GL_TRUE : GL_FALSE,
|
||||
attrib.stride, attrib.pointer
|
||||
);)
|
||||
}
|
||||
|
||||
if (attrib.enabled) {
|
||||
CallAndCheck(::GLES::glEnableVertexAttribArray(index);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisableVertexAttribArray(index);)
|
||||
}
|
||||
}
|
||||
}
|
||||
CallAndCheck(::GLES::glBindVertexArray(0);)
|
||||
//}
|
||||
}
|
||||
GLuint currentMgVAO = vaState->currentVao_;
|
||||
if (s_vaoMap.count(currentMgVAO)) {
|
||||
CallAndCheck(::GLES::glBindVertexArray(s_vaoMap[currentMgVAO]);)
|
||||
|
||||
VertexArrayObject& currentVAO = vaState->vaos_[currentMgVAO];
|
||||
for (auto& [index, attrib] : currentVAO.attribs) {
|
||||
if (attrib.enabled) {
|
||||
CallAndCheck(::GLES::glEnableVertexAttribArray(index);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisableVertexAttribArray(index);)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CallAndCheck(::GLES::glBindVertexArray(0);)
|
||||
}
|
||||
|
||||
// EBO
|
||||
if (vao->elementBuffer != 0) {
|
||||
if (s_bufferMap.count(vao->elementBuffer)) {
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_bufferMap[vao->elementBuffer]);)
|
||||
}
|
||||
} else if (indices != nullptr) {
|
||||
static GLuint dynamicIBO = 0;
|
||||
if (dynamicIBO == 0) {
|
||||
CallAndCheck(::GLES::glGenBuffers(1, &dynamicIBO);)
|
||||
}
|
||||
|
||||
size_t typeSize = 0;
|
||||
switch(type) {
|
||||
case GL_UNSIGNED_BYTE: typeSize = sizeof(GLubyte); break;
|
||||
case GL_UNSIGNED_SHORT: typeSize = sizeof(GLushort); break;
|
||||
case GL_UNSIGNED_INT: typeSize = sizeof(GLuint); break;
|
||||
}
|
||||
size_t dataSize = count * typeSize;
|
||||
|
||||
CallAndCheck(::GLES::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamicIBO);)
|
||||
CallAndCheck(::GLES::glBufferData(GL_ELEMENT_ARRAY_BUFFER, dataSize, indices, GL_STREAM_DRAW);)
|
||||
}
|
||||
|
||||
// Program
|
||||
GLuint currentProgram = programState->GetCurrentProgram();
|
||||
if (currentProgram != lastBoundProgram) {
|
||||
if (s_programMap.find(currentProgram) == s_programMap.end()) {
|
||||
GLuint glProgram = ::GLES::glCreateProgram();
|
||||
ProgramObject& mgProgram = programState->programs_[currentProgram];
|
||||
|
||||
// Shader
|
||||
for (GLuint shaderId : mgProgram.attachedShaders) {
|
||||
ShaderObject& mgShader = programState->shaders_[shaderId];
|
||||
GLuint glShader = ::GLES::glCreateShader(mgShader.type);
|
||||
std::string source = MG_Util::Program::CompileSPIRVToGLSL(mgShader.compiledSpirv, 320, true);
|
||||
// Post-processing ESSL
|
||||
source = removeLayoutBinding(source);
|
||||
source = processOutColorLocations(source);
|
||||
source = forceSupporterOutput(source);
|
||||
MG_Util::Debug::LogD(
|
||||
"shader source:\n%s\nConverted source:\n%s\nSpirv Size:%d",
|
||||
mgShader.source.c_str(),source.c_str(),mgShader.compiledSpirv.size()
|
||||
);
|
||||
|
||||
const char* s[] = { source.c_str() };
|
||||
CallAndCheck(::GLES::glShaderSource(glShader, 1, s, nullptr);)
|
||||
CallAndCheck(::GLES::glCompileShader(glShader);)
|
||||
|
||||
GLint success;
|
||||
CallAndCheck(::GLES::glGetShaderiv(glShader, GL_COMPILE_STATUS, &success);)
|
||||
if (!success) {
|
||||
GLchar infoLog[512];
|
||||
CallAndCheck(::GLES::glGetShaderInfoLog(glShader, 512, nullptr, infoLog);)
|
||||
MG_Util::Debug::LogE("Shader compilation failed: %s", infoLog);
|
||||
}
|
||||
CallAndCheck(::GLES::glAttachShader(glProgram, glShader);)
|
||||
}
|
||||
|
||||
CallAndCheck(::GLES::glLinkProgram(glProgram);)
|
||||
GLint linkStatus;
|
||||
CallAndCheck(::GLES::glGetProgramiv(glProgram, GL_LINK_STATUS, &linkStatus);)
|
||||
if (!linkStatus) {
|
||||
GLchar infoLog[512];
|
||||
CallAndCheck(::GLES::glGetProgramInfoLog(glProgram, 512, nullptr, infoLog);)
|
||||
MG_Util::Debug::LogE("Program linking failed: %s", infoLog);
|
||||
}
|
||||
s_programMap[currentProgram] = glProgram;
|
||||
}
|
||||
CallAndCheck(::GLES::glUseProgram(s_programMap[currentProgram]);)
|
||||
lastBoundProgram = currentProgram;
|
||||
|
||||
// Uniform
|
||||
ProgramObject& mgProgram = programState->programs_[currentProgram];
|
||||
for (auto& [name, uniform] : mgProgram.uniformValues) {
|
||||
GLint location = ::GLES::glGetUniformLocation(s_programMap[currentProgram], name.c_str());
|
||||
if (location == -1) {
|
||||
MG_Util::Debug::LogE("Uniform location not found: %s", name.c_str());
|
||||
continue;
|
||||
}
|
||||
MG_Util::Debug::LogD("Uniform %s(type: %u) location: %u(GLES) -- %u(MG)", name.c_str(), uniform.type, location, mgProgram.uniformLocations[name]);
|
||||
|
||||
switch (uniform.type) {
|
||||
case GL_FLOAT: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 1);
|
||||
CallAndCheck(::GLES::glUniform1fv(location, num, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_VEC2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 2);
|
||||
CallAndCheck(::GLES::glUniform2fv(location, num, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_VEC3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 3);
|
||||
CallAndCheck(::GLES::glUniform3fv(location, num, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_VEC4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 4);
|
||||
CallAndCheck(::GLES::glUniform4fv(location, num, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
|
||||
case GL_INT:
|
||||
case GL_BOOL:
|
||||
case GL_SAMPLER_1D:
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_3D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_2D_SHADOW: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 1);
|
||||
CallAndCheck(::GLES::glUniform1iv(location, num, uniform.intData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_INT_VEC2:
|
||||
case GL_BOOL_VEC2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 2);
|
||||
CallAndCheck(::GLES::glUniform2iv(location, num, uniform.intData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_INT_VEC3:
|
||||
case GL_BOOL_VEC3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 3);
|
||||
CallAndCheck(::GLES::glUniform3iv(location, num, uniform.intData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_INT_VEC4:
|
||||
case GL_BOOL_VEC4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 4);
|
||||
CallAndCheck(::GLES::glUniform4iv(location, num, uniform.intData.data());)
|
||||
break;
|
||||
}
|
||||
|
||||
case GL_UNSIGNED_INT: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 1);
|
||||
CallAndCheck(::GLES::glUniform1uiv(location, num, uniform.uintData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT_VEC2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 2);
|
||||
CallAndCheck(::GLES::glUniform2uiv(location, num, uniform.uintData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT_VEC3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 3);
|
||||
CallAndCheck(::GLES::glUniform3uiv(location, num, uniform.uintData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_UNSIGNED_INT_VEC4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 4);
|
||||
CallAndCheck(::GLES::glUniform4uiv(location, num, uniform.uintData.data());)
|
||||
break;
|
||||
}
|
||||
|
||||
case GL_FLOAT_MAT2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 4);
|
||||
CallAndCheck(::GLES::glUniformMatrix2fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 9);
|
||||
CallAndCheck(::GLES::glUniformMatrix3fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 16);
|
||||
CallAndCheck(::GLES::glUniformMatrix4fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT2x3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 6);
|
||||
CallAndCheck(::GLES::glUniformMatrix2x3fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT2x4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 8);
|
||||
CallAndCheck(::GLES::glUniformMatrix2x4fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT3x2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 6);
|
||||
CallAndCheck(::GLES::glUniformMatrix3x2fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT3x4: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 12);
|
||||
CallAndCheck(::GLES::glUniformMatrix3x4fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT4x2: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 8);
|
||||
CallAndCheck(::GLES::glUniformMatrix4x2fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
case GL_FLOAT_MAT4x3: {
|
||||
GLsizei num = static_cast<GLsizei>(uniform.count / 12);
|
||||
CallAndCheck(::GLES::glUniformMatrix4x3fv(location, num, GL_FALSE, uniform.floatData.data());)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
GLuint currentFBO = fbState->currentBindings_[GL_DRAW_FRAMEBUFFER];
|
||||
if (currentFBO != lastBoundFBO) {
|
||||
GLuint glFBO = 0;
|
||||
|
||||
if (currentFBO == 0) {
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, 0);)
|
||||
glFBO = 0;
|
||||
} else {
|
||||
bool isNewGlesFBO = false;
|
||||
|
||||
if (s_framebufferMap.find(currentFBO) == s_framebufferMap.end()) {
|
||||
CallAndCheck(::GLES::glGenFramebuffers(1, &glFBO);)
|
||||
s_framebufferMap[currentFBO] = glFBO;
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, glFBO);)
|
||||
MG_Util::Debug::LogD("Generated and bound new GLES FBO %u for MobileGL FBO %u", glFBO, currentFBO);
|
||||
GLenum status = ::GLES::glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
MG_Util::Debug::LogE("Framebuffer %u (GLES FBO %u) is not complete after creation! Status: 0x%X (%s)",
|
||||
currentFBO, glFBO, status, MG_Util::Debug::GLEnumToString(status));
|
||||
}
|
||||
isNewGlesFBO = true;
|
||||
} else {
|
||||
glFBO = s_framebufferMap[currentFBO];
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, glFBO);)
|
||||
MG_Util::Debug::LogD("Bound existing GLES FBO %u for MobileGL FBO %u", glFBO, currentFBO);
|
||||
}
|
||||
|
||||
if (glFBO != 0) {
|
||||
FramebufferObject* mgFBO = fbState->GetCurrentFBO(GL_DRAW_FRAMEBUFFER);
|
||||
if (mgFBO) {
|
||||
MG_Util::Debug::LogD("Checking/Syncing attachments for GLES FBO %u (MobileGL FBO %u)", glFBO, currentFBO);
|
||||
|
||||
for (auto const& [mgAttachmentPoint, mgAtt] : mgFBO->attachments) {
|
||||
|
||||
if (mgAtt.type != GL_TEXTURE_2D) {
|
||||
MG_Util::Debug::LogW("Skipping non-TEXTURE_2D attachment 0x%X for FBO %u", mgAttachmentPoint, currentFBO);
|
||||
continue;
|
||||
}
|
||||
|
||||
GLuint expectedGLTexId = 0;
|
||||
if (mgAtt.handle != 0) {
|
||||
if (s_textureMap.count(mgAtt.handle)) {
|
||||
expectedGLTexId = s_textureMap[mgAtt.handle];
|
||||
} else {
|
||||
MG_Util::Debug::LogE("MobileGL Texture %u for FBO %u attachment 0x%X not found in s_textureMap during FBO sync!", mgAtt.handle, currentFBO, mgAttachmentPoint);
|
||||
for (auto const& [key, val] : s_textureMap)
|
||||
MG_Util::Debug::LogW(" key: %d, val: %d", key, val);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GLint glesAttachedType = 0;
|
||||
GLint glesAttachedName = 0;
|
||||
|
||||
CallAndCheck(::GLES::glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, mgAttachmentPoint, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &glesAttachedType);)
|
||||
|
||||
if (glesAttachedType == GL_TEXTURE) {
|
||||
CallAndCheck(::GLES::glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, mgAttachmentPoint, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &glesAttachedName);)
|
||||
} else if (glesAttachedType != GL_NONE) {
|
||||
MG_Util::Debug::LogW("GLES FBO %u attachment 0x%X has non-texture type 0x%X (expected GL_TEXTURE or GL_NONE)", glFBO, mgAttachmentPoint, glesAttachedType);
|
||||
}
|
||||
|
||||
if ((GLuint)glesAttachedName != expectedGLTexId) {
|
||||
MG_Util::Debug::LogD("Syncing FBO %u attachment 0x%X: Expected GLES TexID %u, Found GLES ObjName %d. Attaching/Detaching...",
|
||||
currentFBO, mgAttachmentPoint, expectedGLTexId, glesAttachedName);
|
||||
|
||||
CallAndCheck(::GLES::glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
mgAttachmentPoint,
|
||||
GL_TEXTURE_2D,
|
||||
expectedGLTexId,
|
||||
mgAtt.mipLevel
|
||||
);)
|
||||
}
|
||||
}
|
||||
GLenum status = ::GLES::glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
MG_Util::Debug::LogE("Framebuffer %u (GLES FBO %u) is not complete after sync! Status: 0x%X (%s)",
|
||||
currentFBO, glFBO, status, MG_Util::Debug::GLEnumToString(status));
|
||||
}
|
||||
|
||||
} else {
|
||||
MG_Util::Debug::LogW("Could not get MobileGL FBO object for ID %u during attachment sync.", currentFBO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastBoundFBO = currentFBO;
|
||||
}
|
||||
|
||||
|
||||
if (vao->elementBuffer != 0 || indices != nullptr) {
|
||||
CallAndCheck(::GLES::glDrawElements(
|
||||
mode,
|
||||
count,
|
||||
type,
|
||||
indices
|
||||
);)
|
||||
}
|
||||
}
|
||||
|
||||
void ClearSHITTILY(GLbitfield mask) {
|
||||
CommonState* commonState = MG_State_T::commonState;
|
||||
FramebufferState* fbState = MG_State_T::framebufferState;
|
||||
|
||||
GLuint currentFBO = fbState->currentBindings_[GL_DRAW_FRAMEBUFFER];
|
||||
if (currentFBO != lastBoundFBO) {
|
||||
GLuint glFBO = 0;
|
||||
|
||||
if (currentFBO == 0) {
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, 0);)
|
||||
glFBO = 0;
|
||||
} else {
|
||||
bool isNewGlesFBO = false;
|
||||
|
||||
if (s_framebufferMap.find(currentFBO) == s_framebufferMap.end()) {
|
||||
CallAndCheck(::GLES::glGenFramebuffers(1, &glFBO);)
|
||||
s_framebufferMap[currentFBO] = glFBO;
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, glFBO);)
|
||||
MG_Util::Debug::LogD("Generated and bound new GLES FBO %u for MobileGL FBO %u", glFBO, currentFBO);
|
||||
isNewGlesFBO = true;
|
||||
} else {
|
||||
glFBO = s_framebufferMap[currentFBO];
|
||||
CallAndCheck(::GLES::glBindFramebuffer(GL_FRAMEBUFFER, glFBO);)
|
||||
MG_Util::Debug::LogD("Bound existing GLES FBO %u for MobileGL FBO %u", glFBO, currentFBO);
|
||||
}
|
||||
|
||||
if (glFBO != 0) {
|
||||
FramebufferObject* mgFBO = fbState->GetCurrentFBO(GL_DRAW_FRAMEBUFFER);
|
||||
if (mgFBO) {
|
||||
MG_Util::Debug::LogD("Checking/Syncing attachments for GLES FBO %u (MobileGL FBO %u)", glFBO, currentFBO);
|
||||
|
||||
for (auto const& [mgAttachmentPoint, mgAtt] : mgFBO->attachments) {
|
||||
|
||||
if (mgAtt.type != GL_TEXTURE_2D) {
|
||||
MG_Util::Debug::LogW("Skipping non-TEXTURE_2D attachment 0x%X for FBO %u", mgAttachmentPoint, currentFBO);
|
||||
continue;
|
||||
}
|
||||
|
||||
GLuint expectedGLTexId = 0;
|
||||
if (mgAtt.handle != 0) {
|
||||
if (s_textureMap.count(mgAtt.handle)) {
|
||||
expectedGLTexId = s_textureMap[mgAtt.handle];
|
||||
} else {
|
||||
MG_Util::Debug::LogE("MobileGL Texture %u for FBO %u attachment 0x%X not found in s_textureMap during FBO sync!", mgAtt.handle, currentFBO, mgAttachmentPoint);
|
||||
for (auto const& [key, val] : s_textureMap)
|
||||
MG_Util::Debug::LogW(" key: %d, val: %d", key, val);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GLint glesAttachedType = 0;
|
||||
GLint glesAttachedName = 0;
|
||||
|
||||
CallAndCheck(::GLES::glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, mgAttachmentPoint, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &glesAttachedType);)
|
||||
|
||||
if (glesAttachedType == GL_TEXTURE) {
|
||||
CallAndCheck(::GLES::glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, mgAttachmentPoint, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &glesAttachedName);)
|
||||
} else if (glesAttachedType != GL_NONE) {
|
||||
MG_Util::Debug::LogW("GLES FBO %u attachment 0x%X has non-texture type 0x%X (expected GL_TEXTURE or GL_NONE)", glFBO, mgAttachmentPoint, glesAttachedType);
|
||||
}
|
||||
|
||||
if ((GLuint)glesAttachedName != expectedGLTexId) {
|
||||
MG_Util::Debug::LogD("Syncing FBO %u attachment 0x%X: Expected GLES TexID %u, Found GLES ObjName %d. Attaching/Detaching...",
|
||||
currentFBO, mgAttachmentPoint, expectedGLTexId, glesAttachedName);
|
||||
|
||||
CallAndCheck(::GLES::glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
mgAttachmentPoint,
|
||||
GL_TEXTURE_2D,
|
||||
expectedGLTexId,
|
||||
mgAtt.mipLevel
|
||||
);)
|
||||
}
|
||||
}
|
||||
|
||||
GLenum status = ::GLES::glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
MG_Util::Debug::LogE("Framebuffer %u (GLES FBO %u) is not complete after sync! Status: 0x%X (%s)",
|
||||
currentFBO, glFBO, status, MG_Util::Debug::GLEnumToString(status));
|
||||
}
|
||||
|
||||
} else {
|
||||
MG_Util::Debug::LogW("Could not get MobileGL FBO object for ID %u during attachment sync.", currentFBO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastBoundFBO = currentFBO;
|
||||
}
|
||||
|
||||
|
||||
static GLfloat lastClearColor[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
|
||||
if (memcmp(lastClearColor, commonState->clearColor, sizeof(lastClearColor)) != 0) {
|
||||
CallAndCheck(::GLES::glClearColor(
|
||||
commonState->clearColor[0],
|
||||
commonState->clearColor[1],
|
||||
commonState->clearColor[2],
|
||||
commonState->clearColor[3]
|
||||
);)
|
||||
memcpy(lastClearColor, commonState->clearColor, sizeof(lastClearColor));
|
||||
}
|
||||
|
||||
static GLfloat lastClearDepth = -1.0f;
|
||||
if (lastClearDepth != commonState->clearDepth) {
|
||||
CallAndCheck(::GLES::glClearDepthf(commonState->clearDepth);)
|
||||
lastClearDepth = commonState->clearDepth;
|
||||
}
|
||||
|
||||
static GLint lastClearStencil = -1;
|
||||
GLint currentStencil = 0;
|
||||
if (lastClearStencil != currentStencil) {
|
||||
CallAndCheck(::GLES::glClearStencil(currentStencil);)
|
||||
lastClearStencil = currentStencil;
|
||||
}
|
||||
|
||||
const GLint* viewport = commonState->viewport;
|
||||
if (viewport[2] > 0 && viewport[3] > 0) {
|
||||
CallAndCheck(::GLES::glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_BLEND]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_BLEND);)
|
||||
CallAndCheck(::GLES::glBlendFuncSeparate(
|
||||
commonState->blendSrcRGB, commonState->blendDstRGB,
|
||||
commonState->blendSrcAlpha, commonState->blendDstAlpha
|
||||
);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_BLEND);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_DEPTH_TEST]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_DEPTH_TEST);)
|
||||
CallAndCheck(::GLES::glDepthMask(commonState->depthMask);)
|
||||
CallAndCheck(::GLES::glDepthFunc(commonState->depthFunc);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_DEPTH_TEST);)
|
||||
}
|
||||
|
||||
if (commonState->capabilities[GL_CULL_FACE]) {
|
||||
CallAndCheck(::GLES::glEnable(GL_CULL_FACE);)
|
||||
} else {
|
||||
CallAndCheck(::GLES::glDisable(GL_CULL_FACE);)
|
||||
}
|
||||
|
||||
CallAndCheck(::GLES::glColorMask(
|
||||
commonState->colorMask[0], commonState->colorMask[1],
|
||||
commonState->colorMask[2], commonState->colorMask[3]
|
||||
);)
|
||||
|
||||
CallAndCheck(::GLES::glClear(mask);)
|
||||
|
||||
}
|
||||
|
||||
void Clear(GLbitfield mask) {
|
||||
MG_Util::Debug::LogD("glClear, mask: 0x%X", mask);
|
||||
GLenum result = MG_State::glClear(mask);
|
||||
if (result == GL_NO_ERROR) {
|
||||
ClearSHITTILY(mask);
|
||||
return;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Error clearing buffers: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {
|
||||
::GLES::glViewport(0,0,3200,1440);
|
||||
MG_RHI::GLES::Test::DrawAllTextures();
|
||||
};
|
||||
DrawElementsSHITTILY(mode, count, type, indices);
|
||||
}
|
||||
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
::GLES::glViewport(0,0,3200,1440);
|
||||
MG_RHI::GLES::Test::DrawAllTextures();
|
||||
};
|
||||
DrawArraysSHITTILY(mode, first, count);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#ifndef MOBILEGL_GL_DRAWING_H
|
||||
#define MOBILEGL_GL_DRAWING_H
|
||||
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
|
||||
@@ -32,11 +32,11 @@ public:
|
||||
void Delete(GLuint buffer);
|
||||
GLuint GetCurrentBinding(GLenum target) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_;
|
||||
std::unordered_map<GLuint, BufferObject> buffers_;
|
||||
private:
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_;
|
||||
|
||||
static bool IsValidTarget_(GLenum target);
|
||||
};
|
||||
|
||||
@@ -107,6 +107,7 @@ GLenum CommonState::Clear(GLbitfield mask) {
|
||||
if ((mask & ~validBits) != 0) {
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
clearMask = mask;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,13 @@
|
||||
#include "../../../Includes.h"
|
||||
|
||||
class CommonState {
|
||||
private:
|
||||
public:
|
||||
// Viewport
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
|
||||
// Color mask
|
||||
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
|
||||
|
||||
// Pixel storage parameters
|
||||
std::unordered_map<GLenum, GLint> pixelStoreParams;
|
||||
|
||||
@@ -22,21 +28,15 @@ private:
|
||||
// Clear state
|
||||
GLfloat clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
GLfloat clearDepth = 1.0f;
|
||||
|
||||
// Color mask
|
||||
GLboolean colorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE};
|
||||
|
||||
GLenum clearMask;
|
||||
|
||||
// Depth state
|
||||
GLenum depthFunc = GL_LESS;
|
||||
GLboolean depthMask = GL_TRUE;
|
||||
|
||||
// Viewport
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
|
||||
|
||||
// Capability enables
|
||||
std::unordered_map<GLenum, bool> capabilities;
|
||||
|
||||
public:
|
||||
CommonState();
|
||||
|
||||
// Return: the validity of the operation, according to OpenGL 3 standard
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
GLenum Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
|
||||
GLint QueryPixelStoreInt(GLenum pname);
|
||||
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_COMMONSTATE_H
|
||||
|
||||
@@ -48,7 +48,6 @@ GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
|
||||
if (target == GL_FRAMEBUFFER) {
|
||||
currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer;
|
||||
currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer;
|
||||
currentBindings_[GL_FRAMEBUFFER] = framebuffer;
|
||||
} else {
|
||||
currentBindings_[target] = framebuffer;
|
||||
}
|
||||
@@ -60,6 +59,7 @@ GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment,
|
||||
if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() ||
|
||||
MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end())
|
||||
return GL_INVALID_ENUM;
|
||||
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
if (texture != 0 && !MG_State_T::textureState->IsTexture(texture))
|
||||
@@ -84,6 +84,7 @@ GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment,
|
||||
}
|
||||
|
||||
GLenum FramebufferState::glValidateCompleteness(GLenum target) {
|
||||
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
return fbo->status;
|
||||
|
||||
@@ -35,9 +35,10 @@ public:
|
||||
GLenum glValidateCompleteness(GLenum target);
|
||||
FramebufferObject* GetCurrentFBO(GLenum target);
|
||||
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW/FRAMEBUFFER
|
||||
|
||||
private:
|
||||
std::unordered_map<GLuint, FramebufferObject> framebuffers_;
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW/FRAMEBUFFER
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
bool ValidateHandle(GLuint framebuffer);
|
||||
|
||||
@@ -47,7 +47,7 @@ struct ProgramObject {
|
||||
};
|
||||
|
||||
class ProgramState {
|
||||
private:
|
||||
public:
|
||||
std::unordered_map<GLuint, ShaderObject> shaders_;
|
||||
std::unordered_map<GLuint, ProgramObject> programs_;
|
||||
std::set<GLuint> freeShaderIds_;
|
||||
@@ -56,7 +56,6 @@ private:
|
||||
GLuint lastProgramId_ = 0;
|
||||
GLuint currentProgram_ = 0;
|
||||
|
||||
public:
|
||||
ProgramState();
|
||||
~ProgramState();
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
|
||||
class TextureState {
|
||||
private:
|
||||
std::vector<TextureUnitState> textureUnits_;
|
||||
GLuint activeTextureUnit_ = 0;
|
||||
|
||||
GLuint lastUsedID_ = 0;
|
||||
@@ -88,6 +87,7 @@ public:
|
||||
GLenum DeleteN(GLsizei n, const GLuint* textures);
|
||||
GLenum QueryLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
|
||||
|
||||
std::vector<TextureUnitState> textureUnits_;
|
||||
private:
|
||||
size_t CalculatePixelDataSize_(GLenum format, GLenum type, GLsizei width, GLsizei height);
|
||||
void InvalidateTextureInAllUnits_(GLuint texture);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct VertexAttribState {
|
||||
bool enabled = false;
|
||||
bool enabled;
|
||||
GLint size = 4;
|
||||
GLenum type = GL_FLOAT;
|
||||
GLboolean normalized = GL_FALSE;
|
||||
@@ -43,11 +43,11 @@ public:
|
||||
GLuint GetBoundElementBuffer();
|
||||
VertexArrayObject* GetCurrentVAO();
|
||||
|
||||
private:
|
||||
GLuint currentVao_ = 0;
|
||||
std::unordered_map<GLuint, VertexArrayObject> vaos_;
|
||||
private:
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
GLuint currentVao_ = 0;
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_VERTEXARRAYSTATE_H
|
||||
|
||||
@@ -402,4 +402,39 @@ namespace MG_Util::Program {
|
||||
}
|
||||
spvc_context_destroy(context);
|
||||
}
|
||||
|
||||
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES) {
|
||||
spvc_context context = nullptr;
|
||||
spvc_parsed_ir ir = nullptr;
|
||||
spvc_compiler compiler_glsl = nullptr;
|
||||
spvc_compiler_options options = nullptr;
|
||||
spvc_resources resources = nullptr;
|
||||
const spvc_reflected_resource *list = nullptr;
|
||||
const char *result = nullptr;
|
||||
size_t count;
|
||||
|
||||
const SpvId *p_spirv = spirv.data();
|
||||
size_t word_count = spirv.size();
|
||||
|
||||
spvc_context_create(&context);
|
||||
spvc_context_parse_spirv(context, p_spirv, word_count, &ir);
|
||||
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl);
|
||||
spvc_compiler_create_shader_resources(compiler_glsl, &resources);
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
|
||||
spvc_compiler_create_compiler_options(compiler_glsl, &options);
|
||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, glslVersion);
|
||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, isES ? SPVC_TRUE : SPVC_FALSE);
|
||||
spvc_compiler_install_compiler_options(compiler_glsl, options);
|
||||
spvc_compiler_compile(compiler_glsl, &result);
|
||||
|
||||
if (!result) {
|
||||
return{};
|
||||
}
|
||||
|
||||
std::string essl = result;
|
||||
|
||||
spvc_context_destroy(context);
|
||||
|
||||
return essl;
|
||||
}
|
||||
}
|
||||
@@ -177,6 +177,7 @@ namespace MG_Util::Program {
|
||||
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);
|
||||
std::string CompileSPIRVToGLSL(std::vector<unsigned int> spirv, uint glslVersion, bool isES);
|
||||
}
|
||||
|
||||
#endif //MOBILEGL_GLSLTOOL_H
|
||||
|
||||
Reference in New Issue
Block a user