mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
808 lines
38 KiB
C++
808 lines
38 KiB
C++
//
|
|
// Created by Swung 0x48 on 2025-05-18.
|
|
//
|
|
|
|
#include "EGL_impl.h"
|
|
|
|
#undef MOBILEGL_GLSLTOOL_H
|
|
#undef MOBILEGL_PROGRAM_DEBUGTOOL_H
|
|
#include "../../../../Includes.h"
|
|
|
|
typedef Diligent::IEngineFactoryVk* (*Diligent_GetEngineFactoryVk_t)();
|
|
typedef Diligent::IEngineFactoryOpenGL* (*Diligent_GetEngineFactoryOpenGL_t)();
|
|
|
|
namespace MG_Diligent {
|
|
Diligent::IRenderDevice* g_pDevice;
|
|
Diligent::IDeviceContext* g_pContext;
|
|
Diligent::ISwapChain* g_pSwapChain;
|
|
MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_BufferMap;
|
|
MG_Global::unordered_map<GLuint, Diligent::ITexture*> g_TextureMap;
|
|
MG_Global::unordered_map<GLuint, Diligent::ITextureView*> g_TextureViewMap;
|
|
MG_Global::unordered_map<GLuint, GLFramebufferInfo> g_FramebufferMap;
|
|
MG_Global::unordered_map<GLuint, Diligent::IShader*> g_ShaderMap;
|
|
MG_Global::unordered_map<GLuint, GLProgramInfo> g_ProgramMap;
|
|
MG_Global::unordered_map<GLuint, Diligent::ISampler*> g_SamplerMap;
|
|
MG_Global::unordered_map<GLuint, Diligent::IBuffer*> g_UniformBufferMap;
|
|
bool IsInRenderPass = false;
|
|
bool initialized = false;
|
|
|
|
void PipelineStateManager::ConfigurePSO(
|
|
Diligent::GraphicsPipelineStateCreateInfo &PSOCreateInfo,
|
|
GLProgramInfo &programInfo,
|
|
CommonState &commonState,
|
|
VertexArrayState &vaState,
|
|
GLFramebufferInfo& fbInfo) {
|
|
PSOCreateInfo.PSODesc.Name = "Program_PSO";
|
|
PSOCreateInfo.PSODesc.PipelineType = Diligent::PIPELINE_TYPE_GRAPHICS;
|
|
|
|
__android_log_print(ANDROID_LOG_DEBUG, "Diligent Engine", "Num AttachedShaders: %zu", programInfo.AttachedShaders.size());
|
|
for (auto shader: programInfo.AttachedShaders) {
|
|
__android_log_print(ANDROID_LOG_DEBUG, "Diligent Engine", "AttachedShader: %p, Type: %d", shader, shader->GetDesc().ShaderType);
|
|
switch (shader->GetDesc().ShaderType) {
|
|
case Diligent::SHADER_TYPE_VERTEX:
|
|
PSOCreateInfo.pVS = shader;
|
|
break;
|
|
case Diligent::SHADER_TYPE_PIXEL:
|
|
PSOCreateInfo.pPS = shader;
|
|
break;
|
|
case Diligent::SHADER_TYPE_GEOMETRY:
|
|
PSOCreateInfo.pGS = shader;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements = programInfo.inputLayout.data();
|
|
PSOCreateInfo.GraphicsPipeline.InputLayout.NumElements = programInfo.inputLayout.size();
|
|
|
|
PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
PSOCreateInfo.GraphicsPipeline.NumRenderTargets = fbInfo.ColorRTVs.size();
|
|
for (size_t i = 0; i < fbInfo.ColorRTVs.size(); ++i) {
|
|
if (fbInfo.ColorRTVs[i]) {
|
|
PSOCreateInfo.GraphicsPipeline.RTVFormats[i] =
|
|
fbInfo.ColorRTVs[i]->GetDesc().Format;
|
|
} else {
|
|
PSOCreateInfo.GraphicsPipeline.RTVFormats[i] = Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
}
|
|
}
|
|
|
|
if (fbInfo.DepthStencilFormat != Diligent::TEX_FORMAT_UNKNOWN) {
|
|
PSOCreateInfo.GraphicsPipeline.DSVFormat = fbInfo.DepthStencilFormat;
|
|
} else {
|
|
PSOCreateInfo.GraphicsPipeline.DSVFormat = Diligent::TEX_FORMAT_D32_FLOAT;
|
|
}
|
|
|
|
Diligent::BlendStateDesc &blendDesc = PSOCreateInfo.GraphicsPipeline.BlendDesc;
|
|
blendDesc.IndependentBlendEnable = false;
|
|
blendDesc.RenderTargets[0].BlendEnable = commonState.capabilities[GL_BLEND];
|
|
blendDesc.RenderTargets[0].SrcBlend = ConvertGLBlendFactor(commonState.blendSrcRGB);
|
|
blendDesc.RenderTargets[0].DestBlend = ConvertGLBlendFactor(commonState.blendDstRGB);
|
|
blendDesc.RenderTargets[0].BlendOp = Diligent::BLEND_OPERATION_ADD;
|
|
blendDesc.RenderTargets[0].SrcBlendAlpha = ConvertGLBlendFactor(
|
|
commonState.blendSrcAlpha);
|
|
blendDesc.RenderTargets[0].DestBlendAlpha = ConvertGLBlendFactor(
|
|
commonState.blendDstAlpha);
|
|
blendDesc.RenderTargets[0].BlendOpAlpha = Diligent::BLEND_OPERATION_ADD;
|
|
blendDesc.RenderTargets[0].RenderTargetWriteMask = Diligent::COLOR_MASK_ALL;
|
|
|
|
Diligent::DepthStencilStateDesc &depthStencilDesc = PSOCreateInfo.GraphicsPipeline.DepthStencilDesc;
|
|
depthStencilDesc.DepthEnable = commonState.capabilities[GL_DEPTH_TEST];
|
|
depthStencilDesc.DepthWriteEnable = commonState.depthMask;
|
|
depthStencilDesc.DepthFunc = ConvertGLDepthFunc(commonState.depthFunc);
|
|
|
|
Diligent::RasterizerStateDesc &rasterizerDesc = PSOCreateInfo.GraphicsPipeline.RasterizerDesc;
|
|
rasterizerDesc.CullMode = commonState.capabilities[GL_CULL_FACE] ?
|
|
Diligent::CULL_MODE_BACK : Diligent::CULL_MODE_NONE;
|
|
rasterizerDesc.FrontCounterClockwise = true;
|
|
|
|
ConfigureResourceLayout(PSOCreateInfo, programInfo);
|
|
}
|
|
|
|
void PipelineStateManager::ReleasePSO(GLuint program) {
|
|
auto &programInfo = g_ProgramMap[program];
|
|
if (programInfo.pPipelineState) {
|
|
MG_Util::Debug::LogD("Releasing PSO for program %u", program);
|
|
programInfo.pPipelineState->Release();
|
|
programInfo.pPipelineState = nullptr;
|
|
MG_Util::Debug::LogD("PSO released for program %u", program);
|
|
}
|
|
programInfo.psoDirty = true;
|
|
}
|
|
|
|
void PipelineStateManager::MarkPSODirty(GLuint program) {
|
|
auto &programInfo = g_ProgramMap[program];
|
|
programInfo.psoDirty = true;
|
|
MG_Util::Debug::LogD("Marked PSO dirty for program %u", program);
|
|
}
|
|
|
|
Diligent::IPipelineState *PipelineStateManager::GetOrCreatePSO(
|
|
GLuint program,
|
|
GLProgramInfo &programInfo,
|
|
CommonState &commonState,
|
|
VertexArrayState &vaState,
|
|
GLFramebufferInfo& fbInfo) {
|
|
uint64_t currentStateHash = CalculateStateHash(commonState, vaState, fbInfo);
|
|
|
|
if (programInfo.pPipelineState &&
|
|
programInfo.psoStateHash == currentStateHash &&
|
|
!programInfo.psoDirty) {
|
|
return programInfo.pPipelineState;
|
|
}
|
|
|
|
PSOKey key{program, currentStateHash};
|
|
|
|
auto it = psoCache.find(key);
|
|
if (it != psoCache.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
Diligent::GraphicsPipelineStateCreateInfo PSOCreateInfo;
|
|
ConfigurePSO(PSOCreateInfo, programInfo, commonState, vaState, fbInfo);
|
|
|
|
MG_Util::Debug::LogD("Dumping PSOCreateInfo for program %u:", program);
|
|
MG_Util::Debug::LogD(" PSODesc.Name: %s", PSOCreateInfo.PSODesc.Name);
|
|
MG_Util::Debug::LogD(" PSODesc.PipelineType: %d", PSOCreateInfo.PSODesc.PipelineType);
|
|
MG_Util::Debug::LogD(" PSODesc.ResourceLayout.DefaultVariableType: %d", PSOCreateInfo.PSODesc.ResourceLayout.DefaultVariableType);
|
|
MG_Util::Debug::LogD(" PSODesc.ResourceLayout.NumVariables: %u", PSOCreateInfo.PSODesc.ResourceLayout.NumVariables);
|
|
if (PSOCreateInfo.PSODesc.ResourceLayout.Variables) {
|
|
for (Diligent::Uint32 i = 0; i < PSOCreateInfo.PSODesc.ResourceLayout.NumVariables; ++i) {
|
|
MG_Util::Debug::LogD(" Variable %u:", i);
|
|
MG_Util::Debug::LogD(" Name: %s", PSOCreateInfo.PSODesc.ResourceLayout.Variables[i].Name);
|
|
MG_Util::Debug::LogD(" ShaderStages: %u", PSOCreateInfo.PSODesc.ResourceLayout.Variables[i].ShaderStages);
|
|
MG_Util::Debug::LogD(" Type: %d", PSOCreateInfo.PSODesc.ResourceLayout.Variables[i].Type);
|
|
}
|
|
}
|
|
MG_Util::Debug::LogD(" PSODesc.ResourceLayout.NumImmutableSamplers: %u", PSOCreateInfo.PSODesc.ResourceLayout.NumImmutableSamplers);
|
|
if (PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers) {
|
|
for (Diligent::Uint32 i = 0; i < PSOCreateInfo.PSODesc.ResourceLayout.NumImmutableSamplers; ++i) {
|
|
MG_Util::Debug::LogD(" ImmutableSampler %u:", i);
|
|
MG_Util::Debug::LogD(" ShaderStages: %u", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].ShaderStages);
|
|
MG_Util::Debug::LogD(" SamplerOrTextureName: %s", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].SamplerOrTextureName);
|
|
// SamplerDesc
|
|
MG_Util::Debug::LogD(" Desc.MinFilter: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.MinFilter);
|
|
MG_Util::Debug::LogD(" Desc.MagFilter: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.MagFilter);
|
|
MG_Util::Debug::LogD(" Desc.MipFilter: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.MipFilter);
|
|
MG_Util::Debug::LogD(" Desc.AddressU: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.AddressU);
|
|
MG_Util::Debug::LogD(" Desc.AddressV: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.AddressV);
|
|
MG_Util::Debug::LogD(" Desc.AddressW: %d", PSOCreateInfo.PSODesc.ResourceLayout.ImmutableSamplers[i].Desc.AddressW);
|
|
}
|
|
}
|
|
MG_Util::Debug::LogD(" pVS: %p (Shader Type: %d)", PSOCreateInfo.pVS, PSOCreateInfo.pVS ? PSOCreateInfo.pVS->GetDesc().ShaderType : -1);
|
|
MG_Util::Debug::LogD(" pPS: %p (Shader Type: %d)", PSOCreateInfo.pPS, PSOCreateInfo.pPS ? PSOCreateInfo.pPS->GetDesc().ShaderType : -1);
|
|
MG_Util::Debug::LogD(" pGS: %p (Shader Type: %d)", PSOCreateInfo.pGS, PSOCreateInfo.pGS ? PSOCreateInfo.pGS->GetDesc().ShaderType : -1);
|
|
// GraphicsPipeline
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.InputLayout.NumElements: %u", PSOCreateInfo.GraphicsPipeline.InputLayout.NumElements);
|
|
if (PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements) {
|
|
for (Diligent::Uint32 i = 0; i < PSOCreateInfo.GraphicsPipeline.InputLayout.NumElements; ++i) {
|
|
MG_Util::Debug::LogD(" LayoutElement %u:", i);
|
|
MG_Util::Debug::LogD(" InputIndex: %u", PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements[i].InputIndex);
|
|
MG_Util::Debug::LogD(" BufferSlot: %u", PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements[i].BufferSlot);
|
|
MG_Util::Debug::LogD(" NumComponents: %u", PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements[i].NumComponents);
|
|
MG_Util::Debug::LogD(" ValueType: %d", PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements[i].ValueType);
|
|
MG_Util::Debug::LogD(" IsNormalized: %s", PSOCreateInfo.GraphicsPipeline.InputLayout.LayoutElements[i].IsNormalized ? "true" : "false");
|
|
}
|
|
}
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.PrimitiveTopology: %d", PSOCreateInfo.GraphicsPipeline.PrimitiveTopology);
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.NumRenderTargets: %u", PSOCreateInfo.GraphicsPipeline.NumRenderTargets);
|
|
for (Diligent::Uint8 i = 0; i < PSOCreateInfo.GraphicsPipeline.NumRenderTargets; ++i) {
|
|
MG_Util::Debug::LogD(" RTVFormats[%u]: %d", i, PSOCreateInfo.GraphicsPipeline.RTVFormats[i]);
|
|
}
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.DSVFormat: %d", PSOCreateInfo.GraphicsPipeline.DSVFormat);
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.BlendDesc.IndependentBlendEnable: %s", PSOCreateInfo.GraphicsPipeline.BlendDesc.IndependentBlendEnable ? "true" : "false");
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.DepthStencilDesc.DepthEnable: %s", PSOCreateInfo.GraphicsPipeline.DepthStencilDesc.DepthEnable ? "true" : "false");
|
|
MG_Util::Debug::LogD(" GraphicsPipeline.RasterizerDesc.CullMode: %d", PSOCreateInfo.GraphicsPipeline.RasterizerDesc.CullMode);
|
|
|
|
Diligent::IPipelineState *pNewPSO = nullptr;
|
|
MG_Util::Debug::LogD("Creating new PSO for program %u", program);
|
|
g_pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &pNewPSO);
|
|
if (pNewPSO) {
|
|
MG_Util::Debug::LogD("PSO created successfully for program %u: %p", program, pNewPSO);
|
|
} else {
|
|
MG_Util::Debug::LogE("Failed to create PSO for program %u", program);
|
|
}
|
|
|
|
psoCache[key] = pNewPSO;
|
|
|
|
return pNewPSO;
|
|
}
|
|
|
|
void PipelineStateManager::ConfigureResourceLayout(
|
|
Diligent::GraphicsPipelineStateCreateInfo& PSOCreateInfo,
|
|
const GLProgramInfo& programInfo)
|
|
{
|
|
MG_Util::Debug::LogD("Begin configuring resource layout for pipeline");
|
|
|
|
auto& ResourceLayout = PSOCreateInfo.PSODesc.ResourceLayout;
|
|
ResourceLayout.DefaultVariableType = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
|
|
|
|
static std::vector<Diligent::ShaderResourceVariableDesc> Variables;
|
|
static std::vector<Diligent::ImmutableSamplerDesc> ImmutableSamplers;
|
|
|
|
MG_Global::unordered_map<GLuint, std::string> shaderSourcesMap;
|
|
|
|
ProgramObject programObj = MG_State_T::programState->programs_[programInfo.id];
|
|
|
|
for (GLuint shaderId : programObj.attachedShaders) {
|
|
auto it = MG_State_T::programState->shaders_.find(shaderId);
|
|
if (it != MG_State_T::programState->shaders_.end() &&
|
|
!it->second.markedForDeletion) {
|
|
shaderSourcesMap[it->first] = it->second.source;
|
|
}
|
|
}
|
|
|
|
MG_Util::Program::GenerateDefaultUBOForGLSL_Multi(shaderSourcesMap);
|
|
|
|
for (auto shader : programInfo.AttachedShaders) {
|
|
GLuint shaderId = 0;
|
|
for (auto const& [key, val] : MG_Diligent::g_ShaderMap) {
|
|
if (val == shader) {
|
|
shaderId = key;
|
|
break;
|
|
}
|
|
}
|
|
MG_Util::Debug::LogD("Processing shader ID: %u", shaderId);
|
|
|
|
auto& shaderObj = MG_State_T::programState->shaders_[shaderId];
|
|
|
|
std::string compilationLog;
|
|
auto spirv =
|
|
MG_Util::Program::CompileGLSLToSPIRV(shaderObj.type,
|
|
shaderSourcesMap[shaderId],
|
|
compilationLog);
|
|
if (spirv.empty()) {
|
|
MG_Util::Debug::LogE("Failed to compile shader %u: %s", shaderId, compilationLog.c_str());
|
|
continue;
|
|
} else {
|
|
MG_Util::Debug::LogD("Shader %u (modified) compiled to SPIR-V successfully", shaderId);
|
|
}
|
|
|
|
spvc_context context = nullptr;
|
|
spvc_parsed_ir parsed_ir = nullptr;
|
|
spvc_compiler compiler = nullptr;
|
|
spvc_resources resources = nullptr;
|
|
|
|
spvc_result result = spvc_context_create(&context);
|
|
if (result != SPVC_SUCCESS) {
|
|
MG_Util::Debug::LogE("spvc_context_create failed for shader %u", shaderId);
|
|
continue;
|
|
}
|
|
|
|
result = spvc_context_parse_spirv(context,
|
|
spirv.data(),
|
|
spirv.size(),
|
|
&parsed_ir);
|
|
|
|
if (result != SPVC_SUCCESS) {
|
|
MG_Util::Debug::LogE("spvc_context_parse_spirv failed for shader %u", shaderId);
|
|
spvc_context_destroy(context);
|
|
continue;
|
|
}
|
|
|
|
result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL,
|
|
parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
|
|
|
if (result != SPVC_SUCCESS) {
|
|
MG_Util::Debug::LogE("spvc_context_create_compiler failed for shader %u", shaderId);
|
|
spvc_context_destroy(context);
|
|
continue;
|
|
}
|
|
|
|
result = spvc_compiler_create_shader_resources(compiler, &resources);
|
|
if (result != SPVC_SUCCESS) {
|
|
MG_Util::Debug::LogE("spvc_compiler_create_shader_resources failed for shader %u", shaderId);
|
|
spvc_context_destroy(context);
|
|
continue;
|
|
}
|
|
|
|
Diligent::SHADER_TYPE shaderType;
|
|
switch (shaderObj.type) {
|
|
case GL_VERTEX_SHADER:
|
|
shaderType = Diligent::SHADER_TYPE_VERTEX;
|
|
break;
|
|
case GL_FRAGMENT_SHADER:
|
|
shaderType = Diligent::SHADER_TYPE_PIXEL;
|
|
break;
|
|
case GL_GEOMETRY_SHADER:
|
|
shaderType = Diligent::SHADER_TYPE_GEOMETRY;
|
|
break;
|
|
case GL_COMPUTE_SHADER:
|
|
shaderType = Diligent::SHADER_TYPE_COMPUTE;
|
|
break;
|
|
default:
|
|
shaderType = Diligent::SHADER_TYPE_UNKNOWN;
|
|
}
|
|
|
|
MG_Util::Debug::LogD("Shader %u mapped to Diligent shader type %d", shaderId, shaderType);
|
|
|
|
const spvc_reflected_resource* resourceList = nullptr;
|
|
size_t resourceCount = 0;
|
|
|
|
spvc_resources_get_resource_list_for_type(
|
|
resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER,
|
|
&resourceList, &resourceCount);
|
|
MG_Util::Debug::LogD("Shader %u has %zu uniform buffers", shaderId, resourceCount);
|
|
|
|
for (size_t i = 0; i < resourceCount; i++) {
|
|
bool already_added = false;
|
|
for(const auto& existing_var : Variables) {
|
|
if (strcmp(existing_var.Name, resourceList[i].name) == 0) {
|
|
already_added = true;
|
|
MG_Util::Debug::LogD("Uniform buffer %s already added, skipping.", resourceList[i].name);
|
|
break;
|
|
}
|
|
}
|
|
if (already_added) continue;
|
|
|
|
Diligent::ShaderResourceVariableDesc varDesc;
|
|
varDesc.Name = strdup(resourceList[i].name);
|
|
varDesc.ShaderStages = Diligent::SHADER_TYPE_VS_PS; // TODO
|
|
varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
|
|
MG_Util::Debug::LogD("Uniform buffer: %s, Stage: %u, Type: %u", varDesc.Name, varDesc.ShaderStages, varDesc.Type);
|
|
Variables.push_back(varDesc);
|
|
}
|
|
|
|
spvc_resources_get_resource_list_for_type(
|
|
resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE,
|
|
&resourceList, &resourceCount);
|
|
MG_Util::Debug::LogD("Shader %u has %zu sampled images", shaderId, resourceCount);
|
|
|
|
for (size_t i = 0; i < resourceCount; i++) {
|
|
Diligent::ShaderResourceVariableDesc varDesc;
|
|
varDesc.Name = strdup(resourceList[i].name);
|
|
varDesc.ShaderStages = shaderType;
|
|
varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
|
|
MG_Util::Debug::LogD("Sampled image: %s", varDesc.Name);
|
|
Variables.push_back(varDesc);
|
|
|
|
const char* samplerName = varDesc.Name;
|
|
|
|
if (samplerName) {
|
|
auto& texState = *MG_State_T::textureState;
|
|
GLuint activeTextureUnit = texState.activeTextureUnit_;
|
|
if (activeTextureUnit < texState.textureUnits_.size()) {
|
|
auto& unitState = texState.textureUnits_[activeTextureUnit];
|
|
GLuint boundTexture = unitState.GetBoundTexture(GL_TEXTURE_2D);
|
|
if (boundTexture != 0) {
|
|
auto texIt = texState.textures.find(boundTexture);
|
|
if (texIt != texState.textures.end()) {
|
|
auto& texObj = texIt->second;
|
|
Diligent::ImmutableSamplerDesc samplerDesc;
|
|
samplerDesc.ShaderStages = shaderType;
|
|
samplerDesc.SamplerOrTextureName = samplerName;
|
|
|
|
auto minFilterIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_MIN_FILTER);
|
|
samplerDesc.Desc.MinFilter = (minFilterIt != texObj.params.texPropertiesInt.end()) ?
|
|
ConvertGLFilter(minFilterIt->second) : Diligent::FILTER_TYPE_LINEAR;
|
|
|
|
auto magFilterIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_MAG_FILTER);
|
|
samplerDesc.Desc.MagFilter = (magFilterIt != texObj.params.texPropertiesInt.end()) ?
|
|
ConvertGLFilter(magFilterIt->second) : Diligent::FILTER_TYPE_LINEAR;
|
|
|
|
samplerDesc.Desc.MipFilter = ConvertGLMipFilter(
|
|
minFilterIt != texObj.params.texPropertiesInt.end() ?
|
|
minFilterIt->second : GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
auto wrapSIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_WRAP_S);
|
|
samplerDesc.Desc.AddressU = (wrapSIt != texObj.params.texPropertiesInt.end()) ?
|
|
ConvertGLWrapMode(wrapSIt->second) : Diligent::TEXTURE_ADDRESS_WRAP;
|
|
|
|
auto wrapTIt = texObj.params.texPropertiesInt.find(GL_TEXTURE_WRAP_T);
|
|
samplerDesc.Desc.AddressV = (wrapTIt != texObj.params.texPropertiesInt.end()) ?
|
|
ConvertGLWrapMode(wrapTIt->second) : Diligent::TEXTURE_ADDRESS_WRAP;
|
|
|
|
samplerDesc.Desc.AddressW = Diligent::TEXTURE_ADDRESS_CLAMP;
|
|
|
|
MG_Util::Debug::LogD("Created immutable sampler for: %s", samplerName);
|
|
ImmutableSamplers.push_back(samplerDesc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
spvc_resources_get_resource_list_for_type(
|
|
resources, SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS,
|
|
&resourceList, &resourceCount);
|
|
MG_Util::Debug::LogD("Shader %u has %zu separate samplers", shaderId, resourceCount);
|
|
|
|
for (size_t i = 0; i < resourceCount; i++) {
|
|
Diligent::ShaderResourceVariableDesc varDesc;
|
|
varDesc.Name = strdup(resourceList[i].name);
|
|
varDesc.ShaderStages = shaderType;
|
|
varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
|
|
Variables.push_back(varDesc);
|
|
|
|
Diligent::ImmutableSamplerDesc samplerDesc;
|
|
samplerDesc.ShaderStages = shaderType;
|
|
samplerDesc.Desc.MinFilter = Diligent::FILTER_TYPE_LINEAR;
|
|
samplerDesc.Desc.MagFilter = Diligent::FILTER_TYPE_LINEAR;
|
|
samplerDesc.Desc.MipFilter = Diligent::FILTER_TYPE_LINEAR;
|
|
samplerDesc.Desc.AddressU = Diligent::TEXTURE_ADDRESS_WRAP;
|
|
samplerDesc.Desc.AddressV = Diligent::TEXTURE_ADDRESS_WRAP;
|
|
samplerDesc.Desc.AddressW = Diligent::TEXTURE_ADDRESS_CLAMP;
|
|
samplerDesc.SamplerOrTextureName = resourceList[i].name;
|
|
|
|
MG_Util::Debug::LogD("Added fallback immutable sampler: %s", samplerDesc.SamplerOrTextureName);
|
|
ImmutableSamplers.push_back(samplerDesc);
|
|
}
|
|
|
|
spvc_resources_get_resource_list_for_type(
|
|
resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE,
|
|
&resourceList, &resourceCount);
|
|
MG_Util::Debug::LogD("Shader %u has %zu storage images", shaderId, resourceCount);
|
|
|
|
for (size_t i = 0; i < resourceCount; i++) {
|
|
Diligent::ShaderResourceVariableDesc varDesc;
|
|
varDesc.Name = strdup(resourceList[i].name);
|
|
varDesc.ShaderStages = shaderType;
|
|
varDesc.Type = Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
|
|
MG_Util::Debug::LogD("Storage image: %s", varDesc.Name);
|
|
Variables.push_back(varDesc);
|
|
}
|
|
|
|
spvc_context_destroy(context);
|
|
}
|
|
|
|
if (!Variables.empty()) {
|
|
ResourceLayout.Variables = Variables.data();
|
|
ResourceLayout.NumVariables = static_cast<Diligent::Uint32>(Variables.size());
|
|
MG_Util::Debug::LogD("Added %u shader resource variables", ResourceLayout.NumVariables);
|
|
}
|
|
|
|
if (!ImmutableSamplers.empty()) {
|
|
ResourceLayout.ImmutableSamplers = ImmutableSamplers.data();
|
|
ResourceLayout.NumImmutableSamplers = static_cast<Diligent::Uint32>(ImmutableSamplers.size());
|
|
MG_Util::Debug::LogD("Added %u immutable samplers", ResourceLayout.NumImmutableSamplers);
|
|
for (Diligent::Uint32 i = 0; i < ResourceLayout.NumImmutableSamplers; ++i) {
|
|
MG_Util::Debug::LogD(" ImmutableSampler %u:", i);
|
|
MG_Util::Debug::LogD(" ShaderStages: %u", ResourceLayout.ImmutableSamplers[i].ShaderStages);
|
|
MG_Util::Debug::LogD(" SamplerOrTextureName: %s", ResourceLayout.ImmutableSamplers[i].SamplerOrTextureName);
|
|
MG_Util::Debug::LogD(" Desc.MinFilter: %d", ResourceLayout.ImmutableSamplers[i].Desc.MinFilter);
|
|
MG_Util::Debug::LogD(" Desc.MagFilter: %d", ResourceLayout.ImmutableSamplers[i].Desc.MagFilter);
|
|
MG_Util::Debug::LogD(" Desc.MipFilter: %d", ResourceLayout.ImmutableSamplers[i].Desc.MipFilter);
|
|
MG_Util::Debug::LogD(" Desc.AddressU: %d", ResourceLayout.ImmutableSamplers[i].Desc.AddressU);
|
|
MG_Util::Debug::LogD(" Desc.AddressV: %d", ResourceLayout.ImmutableSamplers[i].Desc.AddressV);
|
|
MG_Util::Debug::LogD(" Desc.AddressW: %d", ResourceLayout.ImmutableSamplers[i].Desc.AddressW);
|
|
}
|
|
}
|
|
|
|
MG_Util::Debug::LogD("Finished configuring resource layout");
|
|
}
|
|
|
|
|
|
PipelineStateManager g_PSOManager;
|
|
}
|
|
|
|
using namespace Diligent;
|
|
|
|
namespace MG_EGL::Diligent {
|
|
void LoadDiligentCoreOpenGL(NativeWindowType window) {
|
|
void *handle = dlopen("libGraphicsEngineOpenGL.so", RTLD_LAZY);
|
|
auto Diligent_GetEngineFactoryOpenGL =
|
|
(Diligent_GetEngineFactoryOpenGL_t) dlsym(handle,
|
|
"Diligent_GetEngineFactoryOpenGL");
|
|
|
|
auto *pFactoryOpenGL = Diligent_GetEngineFactoryOpenGL();
|
|
::Diligent::EngineGLCreateInfo EngineCI;
|
|
auto *nativeWindow = static_cast<ANativeWindow *>(window);
|
|
EngineCI.Window.pAWindow = nativeWindow;
|
|
|
|
::Diligent::SwapChainDesc SCDesc;
|
|
|
|
MG_Util::Debug::LogD("Creating OpenGL device and swap chain");
|
|
pFactoryOpenGL->CreateDeviceAndSwapChainGL(
|
|
EngineCI, &MG_Diligent::g_pDevice, &MG_Diligent::g_pContext, SCDesc, &MG_Diligent::g_pSwapChain);
|
|
if (MG_Diligent::g_pDevice && MG_Diligent::g_pContext && MG_Diligent::g_pSwapChain) {
|
|
MG_Util::Debug::LogD("OpenGL device created: device=%p, context=%p, swapchain=%p",
|
|
MG_Diligent::g_pDevice, MG_Diligent::g_pContext, MG_Diligent::g_pSwapChain);
|
|
} else {
|
|
MG_Util::Debug::LogE("Failed to create OpenGL device");
|
|
}
|
|
}
|
|
|
|
void LoadDiligentCoreVulkan(NativeWindowType window) {
|
|
void *handle = dlopen("libGraphicsEngineVk.so", RTLD_LAZY);
|
|
auto Diligent_GetEngineFactoryVk =
|
|
(Diligent_GetEngineFactoryVk_t) dlsym(handle,
|
|
"Diligent_GetEngineFactoryVk");
|
|
|
|
auto *pFactoryVk = Diligent_GetEngineFactoryVk();
|
|
::Diligent::EngineVkCreateInfo EngineCI;
|
|
|
|
::Diligent::SwapChainDesc SCDesc;
|
|
|
|
MG_Util::Debug::LogD("Creating Vulkan device and contexts");
|
|
pFactoryVk->CreateDeviceAndContextsVk(
|
|
EngineCI, &MG_Diligent::g_pDevice, &MG_Diligent::g_pContext);
|
|
if (MG_Diligent::g_pDevice && MG_Diligent::g_pContext) {
|
|
MG_Util::Debug::LogD("Vulkan device created: device=%p, context=%p",
|
|
MG_Diligent::g_pDevice, MG_Diligent::g_pContext);
|
|
} else {
|
|
MG_Util::Debug::LogE("Failed to create Vulkan device");
|
|
}
|
|
|
|
AndroidNativeWindow nativeWindow{window};
|
|
MG_Util::Debug::LogD("Creating Vulkan swap chain");
|
|
pFactoryVk->CreateSwapChainVk(
|
|
MG_Diligent::g_pDevice, MG_Diligent::g_pContext, SCDesc, nativeWindow, &MG_Diligent::g_pSwapChain);
|
|
if (MG_Diligent::g_pSwapChain) {
|
|
MG_Util::Debug::LogD("Vulkan swap chain created: %p", MG_Diligent::g_pSwapChain);
|
|
} else {
|
|
MG_Util::Debug::LogE("Failed to create Vulkan swap chain");
|
|
}
|
|
}
|
|
|
|
void LoadDiligentCore(NativeWindowType window) {
|
|
switch (DILIGENT_BACKEND_TYPE) {
|
|
case MG_Constants::Backend::BACKEND_DILIGENT_VULKAN:
|
|
LoadDiligentCoreVulkan(window);
|
|
break;
|
|
case MG_Constants::Backend::BACKEND_DILIGENT_OPENGL:
|
|
default:
|
|
LoadDiligentCoreOpenGL(window);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void CreateDefaultRenderPass() {
|
|
::Diligent::RenderPassDesc RPDesc;
|
|
RPDesc.AttachmentCount = 2;
|
|
::Diligent::RenderPassAttachmentDesc Attachments[2];
|
|
RPDesc.pAttachments = Attachments;
|
|
|
|
Attachments[0].Format = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
Attachments[0].InitialState = ::Diligent::RESOURCE_STATE_RENDER_TARGET;
|
|
Attachments[0].FinalState = ::Diligent::RESOURCE_STATE_RENDER_TARGET;
|
|
Attachments[0].LoadOp = ::Diligent::ATTACHMENT_LOAD_OP_CLEAR;
|
|
Attachments[0].StoreOp = ::Diligent::ATTACHMENT_STORE_OP_STORE;
|
|
|
|
Attachments[1].Format = ::Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
|
|
Attachments[1].InitialState = ::Diligent::RESOURCE_STATE_DEPTH_WRITE;
|
|
Attachments[1].FinalState = ::Diligent::RESOURCE_STATE_DEPTH_WRITE;
|
|
Attachments[1].LoadOp = ::Diligent::ATTACHMENT_LOAD_OP_CLEAR;
|
|
Attachments[1].StoreOp = ::Diligent::ATTACHMENT_STORE_OP_STORE;
|
|
|
|
::Diligent::AttachmentReference RTAttachmentRef{0, ::Diligent::RESOURCE_STATE_RENDER_TARGET};
|
|
::Diligent::AttachmentReference DSAttachmentRef{1, ::Diligent::RESOURCE_STATE_DEPTH_WRITE};
|
|
|
|
::Diligent::SubpassDesc Subpasses[1];
|
|
Subpasses[0].RenderTargetAttachmentCount = 1;
|
|
Subpasses[0].pRenderTargetAttachments = &RTAttachmentRef;
|
|
Subpasses[0].pDepthStencilAttachment = &DSAttachmentRef;
|
|
|
|
RPDesc.SubpassCount = 1;
|
|
RPDesc.pSubpasses = Subpasses;
|
|
|
|
MG_Util::Debug::LogD("Creating default render pass");
|
|
MG_Diligent::g_pDevice->CreateRenderPass(RPDesc, &MG_Diligent::g_FramebufferMap[0].pRenderPass);
|
|
if (MG_Diligent::g_FramebufferMap[0].pRenderPass) {
|
|
MG_Util::Debug::LogD("Default render pass created: %p", MG_Diligent::g_FramebufferMap[0].pRenderPass);
|
|
} else {
|
|
MG_Util::Debug::LogE("Failed to create default render pass");
|
|
}
|
|
}
|
|
|
|
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
|
|
const EGLint *attrib_list) {
|
|
LoadDiligentCore(window);
|
|
MG_GL::GL::UpdateDefaultFramebuffer();
|
|
return (EGLSurface) 1;
|
|
}
|
|
|
|
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs,
|
|
EGLint config_size, EGLint *num_config) {
|
|
*num_config = 1;
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx,
|
|
const EGLint *attrib_list) {
|
|
return (EGLContext) 1;
|
|
}
|
|
|
|
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLDisplay eglGetDisplay(NativeDisplayType display) {
|
|
return (EGLDisplay) 1;
|
|
}
|
|
|
|
EGLint eglGetError() {
|
|
return EGL_SUCCESS;
|
|
}
|
|
|
|
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglTerminate(EGLDisplay dpy) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglReleaseThread(void) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLContext eglGetCurrentContext(void) {
|
|
return (EGLContext) 1;
|
|
}
|
|
|
|
EGLBoolean
|
|
eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) {
|
|
if (attribute == EGL_NATIVE_VISUAL_ID)
|
|
*value = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglBindAPI(EGLenum api) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLSurface eglGetCurrentSurface(EGLint readdraw) {
|
|
return (EGLSurface) 1;
|
|
}
|
|
|
|
EGLBoolean
|
|
eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) {
|
|
MG_Util::Debug::LogD("Flushing context");
|
|
MG_Diligent::g_pContext->Flush();
|
|
|
|
MG_Util::Debug::LogD("Presenting swap chain");
|
|
MG_Diligent::g_pSwapChain->Present();
|
|
MG_GL::GL::UpdateDefaultFramebuffer();
|
|
|
|
MG_Util::Debug::LogD("Finishing frame");
|
|
MG_Diligent::g_pContext->FinishFrame();
|
|
|
|
auto& fbInfo = MG_Diligent::g_FramebufferMap[0];
|
|
if (fbInfo.pRenderPass && fbInfo.pFramebuffer) {
|
|
MG_Util::Debug::LogD("Setting render targets: %zu color attachments", fbInfo.ColorRTVs.size());
|
|
MG_Diligent::g_pContext->SetRenderTargets(
|
|
static_cast<Uint32>(fbInfo.ColorRTVs.size()),
|
|
fbInfo.ColorRTVs.data(),
|
|
fbInfo.pDepthStencilRTV,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
|
|
);
|
|
|
|
MG_Util::Debug::LogD("Beginning render pass: pass=%p, fb=%p", fbInfo.pRenderPass, fbInfo.pFramebuffer);
|
|
MG_Diligent::g_pContext->BeginRenderPass(
|
|
::Diligent::BeginRenderPassAttribs{
|
|
fbInfo.pRenderPass,
|
|
fbInfo.pFramebuffer,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION
|
|
}
|
|
);
|
|
}
|
|
const auto& SCDesc = MG_Diligent::g_pSwapChain->GetDesc();
|
|
MG_Util::Debug::LogD("Setting viewport: width=%d, height=%d", SCDesc.Width, SCDesc.Height);
|
|
MG_Diligent::g_pContext->SetViewports(1, nullptr, 0, 0);
|
|
return EGL_TRUE;
|
|
}
|
|
|
|
EGLSurface
|
|
eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) {
|
|
return (EGLSurface) 1;
|
|
}
|
|
|
|
}
|
|
|
|
void *libGLES = nullptr, *libEGL = nullptr;
|
|
|
|
static const char *LibPathPrefixes[] = {
|
|
"",
|
|
"/opt/vc/lib/",
|
|
"/usr/local/lib/",
|
|
"/usr/lib/",
|
|
nullptr
|
|
};
|
|
|
|
static const char *LibExts[] = {
|
|
"so",
|
|
"so.1",
|
|
"so.2",
|
|
"dylib",
|
|
"dll",
|
|
nullptr
|
|
};
|
|
|
|
static const char *GLES3Libs[] = {
|
|
"libGLESv3_CM",
|
|
"libGLESv3",
|
|
nullptr
|
|
};
|
|
|
|
static const char *EGLLibs[] = {
|
|
"libEGL",
|
|
nullptr
|
|
};
|
|
|
|
void *OpenLib(const char **names, const char *override) {
|
|
void *lib = nullptr;
|
|
|
|
char path_name[PATH_MAX + 1];
|
|
int flags = RTLD_LOCAL | RTLD_NOW;
|
|
if (override) {
|
|
if ((lib = dlopen(override, flags))) {
|
|
strncpy(path_name, override, PATH_MAX);
|
|
return lib;
|
|
} else {
|
|
MG_Util::Debug::LogE("LIBGL_GLES override failed: %s\n", dlerror());
|
|
}
|
|
}
|
|
for (int p = 0; LibPathPrefixes[p]; p++) {
|
|
for (int i = 0; names[i]; i++) {
|
|
for (int e = 0; LibExts[e]; e++) {
|
|
snprintf(path_name, PATH_MAX, "%s%s.%s", LibPathPrefixes[p], names[i], LibExts[e]);
|
|
if ((lib = dlopen(path_name, flags))) {
|
|
return lib;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return lib;
|
|
}
|
|
|
|
typedef __eglMustCastToProperFunctionPointerType (* eglGetProcAddress_t)(const char *procname);
|
|
eglGetProcAddress_t real_eglGetProcAddress = nullptr;
|
|
|
|
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) {
|
|
if (strncmp(procname, "eglGetProcAddress", strlen("eglGetProcAddress")) == 0) {
|
|
return (__eglMustCastToProperFunctionPointerType)(&eglGetProcAddress);
|
|
}
|
|
|
|
#define MG_EGL_PROC_EXPORT(name) \
|
|
if (strncmp(procname, #name, strlen(#name)) == 0) { \
|
|
return (__eglMustCastToProperFunctionPointerType)(&MG_EGL::Diligent::name); \
|
|
}
|
|
|
|
MG_EGL_PROC_EXPORT(eglCreateWindowSurface);
|
|
MG_EGL_PROC_EXPORT(eglChooseConfig);
|
|
MG_EGL_PROC_EXPORT(eglCreateContext);
|
|
MG_EGL_PROC_EXPORT(eglInitialize);
|
|
MG_EGL_PROC_EXPORT(eglGetDisplay);
|
|
MG_EGL_PROC_EXPORT(eglGetError);
|
|
MG_EGL_PROC_EXPORT(eglMakeCurrent);
|
|
MG_EGL_PROC_EXPORT(eglDestroyContext);
|
|
MG_EGL_PROC_EXPORT(eglDestroySurface);
|
|
MG_EGL_PROC_EXPORT(eglTerminate);
|
|
MG_EGL_PROC_EXPORT(eglReleaseThread);
|
|
MG_EGL_PROC_EXPORT(eglGetCurrentContext);
|
|
MG_EGL_PROC_EXPORT(eglGetConfigAttrib);
|
|
MG_EGL_PROC_EXPORT(eglBindAPI);
|
|
MG_EGL_PROC_EXPORT(eglGetCurrentSurface);
|
|
MG_EGL_PROC_EXPORT(eglQuerySurface);
|
|
MG_EGL_PROC_EXPORT(eglSwapInterval);
|
|
MG_EGL_PROC_EXPORT(eglSwapBuffers);
|
|
MG_EGL_PROC_EXPORT(eglCreatePbufferSurface);
|
|
#undef MG_EGL_PROC_EXPORT
|
|
|
|
/* TODO: Call real eglGetProcAddress() to get the rest (should be real native GLES functions) */
|
|
if (!libEGL) {
|
|
libEGL = OpenLib(EGLLibs, nullptr);
|
|
real_eglGetProcAddress = (eglGetProcAddress_t)dlsym(libEGL, "eglGetProcAddress");
|
|
}
|
|
if (real_eglGetProcAddress)
|
|
return real_eglGetProcAddress(procname);
|
|
|
|
return nullptr;
|
|
} |