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