1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "pipeline_state_object_gles.h"
17 
18 #include <base/containers/fixed_string.h>
19 #include <base/util/formats.h>
20 #include <render/device/pipeline_layout_desc.h>
21 #include <render/device/pipeline_state_desc.h>
22 #include <render/namespace.h>
23 
24 #include "gles/device_gles.h"
25 #include "gles/gl_functions.h"
26 #include "gles/gpu_program_gles.h"
27 #include "util/log.h"
28 
29 using namespace BASE_NS;
30 
31 RENDER_BEGIN_NAMESPACE()
32 namespace {
FormatToVertexType(const VertexInputDeclaration::VertexInputAttributeDescription & attributeRef,GLuint & count,GLenum & type,GLboolean & normalized,bool & isFloat)33 void FormatToVertexType(const VertexInputDeclaration::VertexInputAttributeDescription& attributeRef, GLuint& count,
34     GLenum& type, GLboolean& normalized, bool& isFloat)
35 {
36     if (attributeRef.format == BASE_FORMAT_R16G16_SFLOAT) {
37         count = 2;
38         type = GL_HALF_FLOAT;
39         normalized = false;
40         isFloat = true;
41     } else if (attributeRef.format == BASE_FORMAT_R16G16B16_SFLOAT) {
42         count = 3;
43         type = GL_HALF_FLOAT;
44         normalized = false;
45         isFloat = true;
46     } else if (attributeRef.format == BASE_FORMAT_R16G16B16A16_SNORM) {
47         count = 4;
48         type = GL_SHORT;
49         normalized = true;
50         isFloat = true;
51     } else if (attributeRef.format == BASE_FORMAT_R16G16B16A16_SFLOAT) {
52         count = 4;
53         type = GL_HALF_FLOAT;
54         normalized = false;
55         isFloat = true;
56     } else if (attributeRef.format == BASE_FORMAT_R32G32B32_SFLOAT) {
57         count = 3;
58         type = GL_FLOAT;
59         normalized = false;
60         isFloat = true;
61     } else if (attributeRef.format == BASE_FORMAT_R32G32B32A32_SFLOAT) {
62         count = 4;
63         type = GL_FLOAT;
64         normalized = false;
65         isFloat = true;
66     } else if (attributeRef.format == BASE_FORMAT_R32G32_SFLOAT) {
67         count = 2;
68         type = GL_FLOAT;
69         normalized = false;
70         isFloat = true;
71     } else if (attributeRef.format == BASE_FORMAT_R32_SFLOAT) {
72         count = 1;
73         type = GL_FLOAT;
74         normalized = false;
75         isFloat = true;
76     } else if (attributeRef.format == BASE_FORMAT_R8G8B8A8_UINT) {
77         count = 4;
78         type = GL_UNSIGNED_BYTE;
79         normalized = false;
80         isFloat = false;
81     } else if (attributeRef.format == BASE_FORMAT_R8G8B8A8_UNORM) {
82         count = 4;
83         type = GL_UNSIGNED_BYTE;
84         normalized = true;
85         isFloat = true;
86     } else if (attributeRef.format == BASE_FORMAT_R32G32B32A32_UINT) {
87         count = 4;
88         type = GL_UNSIGNED_INT;
89         normalized = false;
90         isFloat = false;
91     } else if (attributeRef.format == BASE_FORMAT_R32_UINT) {
92         count = 1;
93         type = GL_UNSIGNED_INT;
94         normalized = false;
95         isFloat = false;
96     } else {
97         PLUGIN_ASSERT_MSG(false, "Unhandled attribute format");
98     }
99 }
100 
GetDynamicStateFlags(const array_view<const DynamicStateEnum> dynamicStates)101 DynamicStateFlags GetDynamicStateFlags(const array_view<const DynamicStateEnum> dynamicStates)
102 {
103     DynamicStateFlags flags = 0;
104     for (const auto& ref : dynamicStates) {
105         switch (ref) {
106             case CORE_DYNAMIC_STATE_ENUM_VIEWPORT:
107                 flags |= CORE_DYNAMIC_STATE_VIEWPORT;
108                 break;
109             case CORE_DYNAMIC_STATE_ENUM_SCISSOR:
110                 flags |= CORE_DYNAMIC_STATE_SCISSOR;
111                 break;
112             case CORE_DYNAMIC_STATE_ENUM_LINE_WIDTH:
113                 flags |= CORE_DYNAMIC_STATE_LINE_WIDTH;
114                 break;
115             case CORE_DYNAMIC_STATE_ENUM_DEPTH_BIAS:
116                 flags |= CORE_DYNAMIC_STATE_DEPTH_BIAS;
117                 break;
118             case CORE_DYNAMIC_STATE_ENUM_BLEND_CONSTANTS:
119                 flags |= CORE_DYNAMIC_STATE_BLEND_CONSTANTS;
120                 break;
121             case CORE_DYNAMIC_STATE_ENUM_DEPTH_BOUNDS:
122                 flags |= CORE_DYNAMIC_STATE_DEPTH_BOUNDS;
123                 break;
124             case CORE_DYNAMIC_STATE_ENUM_STENCIL_COMPARE_MASK:
125                 flags |= CORE_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
126                 break;
127             case CORE_DYNAMIC_STATE_ENUM_STENCIL_WRITE_MASK:
128                 flags |= CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK;
129                 break;
130             case CORE_DYNAMIC_STATE_ENUM_STENCIL_REFERENCE:
131                 flags |= CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK;
132                 break;
133             default:
134                 break;
135         }
136     }
137     return flags;
138 }
139 
HighestBit(uint32_t value)140 uint32_t HighestBit(uint32_t value)
141 {
142     uint32_t count = 0;
143     while (value) {
144         ++count;
145         value >>= 1U;
146     }
147     return count;
148 }
149 } // namespace
150 
GraphicsPipelineStateObjectGLES(Device & device,const GpuShaderProgram & gpuShaderProgram,const GraphicsState & graphicsState,const PipelineLayout & pipelineLayout,const VertexInputDeclarationView & vertexInputDeclaration,const ShaderSpecializationConstantDataView & specializationConstants,const array_view<const DynamicStateEnum> dynamicStates,const RenderPassDesc & renderPassDesc,const array_view<const RenderPassSubpassDesc> & renderPassSubpassDescs,const uint32_t subpassIndex)151 GraphicsPipelineStateObjectGLES::GraphicsPipelineStateObjectGLES(Device& device,
152     const GpuShaderProgram& gpuShaderProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
153     const VertexInputDeclarationView& vertexInputDeclaration,
154     const ShaderSpecializationConstantDataView& specializationConstants,
155     const array_view<const DynamicStateEnum> dynamicStates, const RenderPassDesc& renderPassDesc,
156     const array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs, const uint32_t subpassIndex)
157     : GraphicsPipelineStateObject(), device_((DeviceGLES&)device)
158 {
159     plat_.graphicsState = graphicsState;
160     plat_.pipelineLayout = pipelineLayout;
161     for (const auto& t : vertexInputDeclaration.attributeDescriptions) {
162         plat_.vertexInputDeclaration.attributeDescriptions[plat_.vertexInputDeclaration.attributeDescriptionCount] = t;
163         plat_.vertexInputDeclaration.attributeDescriptionCount++;
164     }
165     for (const auto& t : vertexInputDeclaration.bindingDescriptions) {
166         plat_.vertexInputDeclaration.bindingDescriptions[plat_.vertexInputDeclaration.bindingDescriptionCount] = t;
167         plat_.vertexInputDeclaration.bindingDescriptionCount++;
168     }
169     plat_.renderPassDesc = renderPassDesc;
170     plat_.dynamicStateFlags = GetDynamicStateFlags(dynamicStates);
171 
172     const auto& source = static_cast<const GpuShaderProgramGLES&>(gpuShaderProgram);
173 
174     uint32_t views = 0U;
175     for (const auto& subpass : renderPassSubpassDescs) {
176         views = Math::max(HighestBit(subpass.viewMask), views);
177     }
178     plat_.views = views;
179 
180     specialized_ = source.Specialize(specializationConstants, views);
181     plat_.graphicsShader = specialized_.get();
182     if (plat_.graphicsShader) {
183         MakeVAO();
184     }
185 }
186 
GetOESProgram(array_view<const OES_Bind> oesBinds) const187 GpuShaderProgramGLES* GraphicsPipelineStateObjectGLES::GetOESProgram(array_view<const OES_Bind> oesBinds) const
188 {
189     BASE_NS::string key;
190     for (auto& bind : oesBinds) {
191         key += BASE_NS::to_string(bind.set);
192         key += '_';
193         key += BASE_NS::to_string(bind.bind);
194         key += '_';
195     }
196     if (auto it = oesPrograms_.find(key); it != oesPrograms_.end()) {
197         // return existing.
198         return it->second.get();
199     }
200     // create new one.
201     return oesPrograms_.insert({ key, specialized_->OesPatch(oesBinds, plat_.views) }).first->second.get();
202 }
203 
MakeVAO()204 void GraphicsPipelineStateObjectGLES::MakeVAO() noexcept
205 {
206     PLUGIN_ASSERT(device_.IsActive());
207     if (plat_.vao == 0) {
208         const auto& shaderdata = (const GpuShaderProgramPlatformDataGL&)plat_.graphicsShader->GetPlatformData();
209         PLUGIN_ASSERT(shaderdata.program != 0);
210         const uint32_t curVAO = device_.BoundVertexArray();
211         plat_.vao = device_.CreateVertexArray();
212         device_.BindVertexArray(plat_.vao);
213         const VertexInputDeclarationData& vertexInputDecl = plat_.vertexInputDeclaration;
214         for (size_t idx = 0; idx < vertexInputDecl.attributeDescriptionCount; ++idx) {
215             if (shaderdata.inputs[idx] != Gles::INVALID_LOCATION) {
216                 const auto& attributeRef = vertexInputDecl.attributeDescriptions[idx];
217                 GLuint count = 2;
218                 GLenum type = GL_FLOAT;
219                 GLboolean normalized = false;
220                 bool isFloat = false;
221                 FormatToVertexType(attributeRef, count, type, normalized, isFloat);
222                 glEnableVertexAttribArray((GLuint)idx);
223                 glVertexAttribBinding((GLuint)idx, attributeRef.binding);
224                 if (isFloat) {
225                     glVertexAttribFormat((GLuint)idx, (GLint)count, type, normalized, (GLuint)attributeRef.offset);
226                 } else {
227                     glVertexAttribIFormat((GLuint)idx, (GLint)count, type, (GLuint)attributeRef.offset);
228                 }
229             } else {
230                 glDisableVertexAttribArray((GLuint)idx);
231             }
232         }
233         device_.BindVertexArray(curVAO);
234     }
235 }
236 
~GraphicsPipelineStateObjectGLES()237 GraphicsPipelineStateObjectGLES::~GraphicsPipelineStateObjectGLES()
238 {
239     if (plat_.vao) {
240         PLUGIN_ASSERT(device_.IsActive());
241         device_.DeleteVertexArray(plat_.vao);
242     }
243 }
244 
GetPlatformData() const245 const PipelineStateObjectPlatformDataGL& GraphicsPipelineStateObjectGLES::GetPlatformData() const
246 {
247     return plat_;
248 }
249 
ComputePipelineStateObjectGLES(Device & device,const GpuComputeProgram & gpuComputeProgram,const PipelineLayout & pipelineLayout,const ShaderSpecializationConstantDataView & specializationConstants)250 ComputePipelineStateObjectGLES::ComputePipelineStateObjectGLES(Device& device,
251     const GpuComputeProgram& gpuComputeProgram, const PipelineLayout& pipelineLayout,
252     const ShaderSpecializationConstantDataView& specializationConstants)
253     : ComputePipelineStateObject(), device_((DeviceGLES&)device)
254 {
255     PLUGIN_UNUSED(device_);
256     plat_.pipelineLayout = pipelineLayout;
257     const auto& source = static_cast<const GpuComputeProgramGLES&>(gpuComputeProgram);
258     specialized_ = source.Specialize(specializationConstants);
259     plat_.computeShader = specialized_.get();
260 }
261 
262 ComputePipelineStateObjectGLES::~ComputePipelineStateObjectGLES() = default;
263 
GetPlatformData() const264 const PipelineStateObjectPlatformDataGL& ComputePipelineStateObjectGLES::GetPlatformData() const
265 {
266     return plat_;
267 }
268 RENDER_END_NAMESPACE()
269