/*
* Copyright (C) 2023 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 "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");
}
}
} // namespace
GraphicsPipelineStateObjectGLES::GraphicsPipelineStateObjectGLES(Device& device,
const GpuShaderProgram& gpuShaderProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
const VertexInputDeclarationView& vertexInputDeclaration,
const ShaderSpecializationConstantDataView& specializationConstants, const DynamicStateFlags dynamicStateFlags,
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 = dynamicStateFlags;
const auto* source = (const GpuShaderProgramGLES*)&gpuShaderProgram;
specialized_.reset(source->Specialize(specializationConstants));
plat_.graphicsShader = specialized_.get();
MakeVAO();
}
GpuShaderProgramGLES* GraphicsPipelineStateObjectGLES::GetOESProgram(const vector& oes_binds) const
{
BASE_NS::string key;
char tmp[16];
for (auto& bind : oes_binds) {
if (sprintf_s(tmp, sizeof(tmp), "%hhu_%hhu_", bind.set, bind.bind) < 0) {
PLUGIN_LOG_E("GetOESProgram: sprintf_s failed");
}
key += tmp;
}
if (auto it = oesPrograms_.find(key); it != oesPrograms_.end()) {
// return existing.
return it->second.get();
}
// create new one.
unique_ptr prog(specialized_->OesPatch(array_view { oes_binds }));
return oesPrograms_.insert({ key, move(prog) }).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 = (const GpuComputeProgramGLES*)&gpuComputeProgram;
plat_.computeShader = specialized_ = source->Specialize(specializationConstants);
PLUGIN_ASSERT(device_.IsActive());
const auto& shaderdata = (const GpuComputeProgramPlatformDataGL&)plat_.computeShader->GetPlatformData();
PLUGIN_UNUSED(shaderdata);
PLUGIN_ASSERT(shaderdata.program != 0);
}
ComputePipelineStateObjectGLES::~ComputePipelineStateObjectGLES()
{
delete specialized_;
}
const PipelineStateObjectPlatformDataGL& ComputePipelineStateObjectGLES::GetPlatformData() const
{
return plat_;
}
RENDER_END_NAMESPACE()