/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pipeline_state_object_gles.h" #include #include #include #include #include #include "gles/device_gles.h" #include "gles/gl_functions.h" #include "gles/gpu_program_gles.h" #include "util/log.h" using namespace BASE_NS; RENDER_BEGIN_NAMESPACE() namespace { void FormatToVertexType(const VertexInputDeclaration::VertexInputAttributeDescription& attributeRef, GLuint& count, GLenum& type, GLboolean& normalized, bool& isFloat) { if (attributeRef.format == BASE_FORMAT_R16G16_SFLOAT) { count = 2; type = GL_HALF_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R16G16B16_SFLOAT) { count = 3; type = GL_HALF_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R16G16B16A16_SNORM) { count = 4; type = GL_SHORT; normalized = true; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R16G16B16A16_SFLOAT) { count = 4; type = GL_HALF_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R32G32B32_SFLOAT) { count = 3; type = GL_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R32G32B32A32_SFLOAT) { count = 4; type = GL_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R32G32_SFLOAT) { count = 2; type = GL_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R32_SFLOAT) { count = 1; type = GL_FLOAT; normalized = false; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R8G8B8A8_UINT) { count = 4; type = GL_UNSIGNED_BYTE; normalized = false; isFloat = false; } else if (attributeRef.format == BASE_FORMAT_R8G8B8A8_UNORM) { count = 4; type = GL_UNSIGNED_BYTE; normalized = true; isFloat = true; } else if (attributeRef.format == BASE_FORMAT_R32G32B32A32_UINT) { count = 4; type = GL_UNSIGNED_INT; normalized = false; isFloat = false; } else if (attributeRef.format == BASE_FORMAT_R32_UINT) { count = 1; type = GL_UNSIGNED_INT; normalized = false; isFloat = false; } else { PLUGIN_ASSERT_MSG(false, "Unhandled attribute format"); } } DynamicStateFlags GetDynamicStateFlags(const array_view dynamicStates) { DynamicStateFlags flags = 0; for (const auto& ref : dynamicStates) { switch (ref) { case CORE_DYNAMIC_STATE_ENUM_VIEWPORT: flags |= CORE_DYNAMIC_STATE_VIEWPORT; break; case CORE_DYNAMIC_STATE_ENUM_SCISSOR: flags |= CORE_DYNAMIC_STATE_SCISSOR; break; case CORE_DYNAMIC_STATE_ENUM_LINE_WIDTH: flags |= CORE_DYNAMIC_STATE_LINE_WIDTH; break; case CORE_DYNAMIC_STATE_ENUM_DEPTH_BIAS: flags |= CORE_DYNAMIC_STATE_DEPTH_BIAS; break; case CORE_DYNAMIC_STATE_ENUM_BLEND_CONSTANTS: flags |= CORE_DYNAMIC_STATE_BLEND_CONSTANTS; break; case CORE_DYNAMIC_STATE_ENUM_DEPTH_BOUNDS: flags |= CORE_DYNAMIC_STATE_DEPTH_BOUNDS; break; case CORE_DYNAMIC_STATE_ENUM_STENCIL_COMPARE_MASK: flags |= CORE_DYNAMIC_STATE_STENCIL_COMPARE_MASK; break; case CORE_DYNAMIC_STATE_ENUM_STENCIL_WRITE_MASK: flags |= CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK; break; case CORE_DYNAMIC_STATE_ENUM_STENCIL_REFERENCE: flags |= CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK; break; default: break; } } return flags; } uint32_t HighestBit(uint32_t value) { uint32_t count = 0; while (value) { ++count; value >>= 1U; } return count; } } // namespace GraphicsPipelineStateObjectGLES::GraphicsPipelineStateObjectGLES(Device& device, const GpuShaderProgram& gpuShaderProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout, const VertexInputDeclarationView& vertexInputDeclaration, const ShaderSpecializationConstantDataView& specializationConstants, const array_view dynamicStates, const RenderPassDesc& renderPassDesc, const array_view& renderPassSubpassDescs, const uint32_t subpassIndex) : GraphicsPipelineStateObject(), device_((DeviceGLES&)device) { plat_.graphicsState = graphicsState; plat_.pipelineLayout = pipelineLayout; for (const auto& t : vertexInputDeclaration.attributeDescriptions) { plat_.vertexInputDeclaration.attributeDescriptions[plat_.vertexInputDeclaration.attributeDescriptionCount] = t; plat_.vertexInputDeclaration.attributeDescriptionCount++; } for (const auto& t : vertexInputDeclaration.bindingDescriptions) { plat_.vertexInputDeclaration.bindingDescriptions[plat_.vertexInputDeclaration.bindingDescriptionCount] = t; plat_.vertexInputDeclaration.bindingDescriptionCount++; } plat_.renderPassDesc = renderPassDesc; plat_.dynamicStateFlags = GetDynamicStateFlags(dynamicStates); const auto& source = static_cast(gpuShaderProgram); uint32_t views = 0U; for (const auto& subpass : renderPassSubpassDescs) { views = Math::max(HighestBit(subpass.viewMask), views); } plat_.views = views; specialized_ = source.Specialize(specializationConstants, views); plat_.graphicsShader = specialized_.get(); if (plat_.graphicsShader) { MakeVAO(); } } GpuShaderProgramGLES* GraphicsPipelineStateObjectGLES::GetOESProgram(array_view oesBinds) const { BASE_NS::string key; for (auto& bind : oesBinds) { key += BASE_NS::to_string(bind.set); key += '_'; key += BASE_NS::to_string(bind.bind); key += '_'; } if (auto it = oesPrograms_.find(key); it != oesPrograms_.end()) { // return existing. return it->second.get(); } // create new one. return oesPrograms_.insert({ key, specialized_->OesPatch(oesBinds, plat_.views) }).first->second.get(); } void GraphicsPipelineStateObjectGLES::MakeVAO() noexcept { PLUGIN_ASSERT(device_.IsActive()); if (plat_.vao == 0) { const auto& shaderdata = (const GpuShaderProgramPlatformDataGL&)plat_.graphicsShader->GetPlatformData(); PLUGIN_ASSERT(shaderdata.program != 0); const uint32_t curVAO = device_.BoundVertexArray(); plat_.vao = device_.CreateVertexArray(); device_.BindVertexArray(plat_.vao); const VertexInputDeclarationData& vertexInputDecl = plat_.vertexInputDeclaration; for (size_t idx = 0; idx < vertexInputDecl.attributeDescriptionCount; ++idx) { if (shaderdata.inputs[idx] != Gles::INVALID_LOCATION) { const auto& attributeRef = vertexInputDecl.attributeDescriptions[idx]; GLuint count = 2; GLenum type = GL_FLOAT; GLboolean normalized = false; bool isFloat = false; FormatToVertexType(attributeRef, count, type, normalized, isFloat); glEnableVertexAttribArray((GLuint)idx); glVertexAttribBinding((GLuint)idx, attributeRef.binding); if (isFloat) { glVertexAttribFormat((GLuint)idx, (GLint)count, type, normalized, (GLuint)attributeRef.offset); } else { glVertexAttribIFormat((GLuint)idx, (GLint)count, type, (GLuint)attributeRef.offset); } } else { glDisableVertexAttribArray((GLuint)idx); } } device_.BindVertexArray(curVAO); } } GraphicsPipelineStateObjectGLES::~GraphicsPipelineStateObjectGLES() { if (plat_.vao) { PLUGIN_ASSERT(device_.IsActive()); device_.DeleteVertexArray(plat_.vao); } } const PipelineStateObjectPlatformDataGL& GraphicsPipelineStateObjectGLES::GetPlatformData() const { return plat_; } ComputePipelineStateObjectGLES::ComputePipelineStateObjectGLES(Device& device, const GpuComputeProgram& gpuComputeProgram, const PipelineLayout& pipelineLayout, const ShaderSpecializationConstantDataView& specializationConstants) : ComputePipelineStateObject(), device_((DeviceGLES&)device) { PLUGIN_UNUSED(device_); plat_.pipelineLayout = pipelineLayout; const auto& source = static_cast(gpuComputeProgram); specialized_ = source.Specialize(specializationConstants); plat_.computeShader = specialized_.get(); } ComputePipelineStateObjectGLES::~ComputePipelineStateObjectGLES() = default; const PipelineStateObjectPlatformDataGL& ComputePipelineStateObjectGLES::GetPlatformData() const { return plat_; } RENDER_END_NAMESPACE()