1 /*
2 * Copyright (c) 2022 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_R8_UINT) {
92 count = 1;
93 type = GL_UNSIGNED_BYTE;
94 normalized = false;
95 isFloat = false;
96 } else if (attributeRef.format == BASE_FORMAT_R16_UINT) {
97 count = 1;
98 type = GL_UNSIGNED_SHORT;
99 normalized = false;
100 isFloat = false;
101 } else if (attributeRef.format == BASE_FORMAT_R32_UINT) {
102 count = 1;
103 type = GL_UNSIGNED_INT;
104 normalized = false;
105 isFloat = false;
106 } else {
107 PLUGIN_ASSERT_MSG(false, "Unhandled attribute format: %d", attributeRef.format);
108 }
109 }
110
GetDynamicStateFlags(const array_view<const DynamicStateEnum> dynamicStates)111 DynamicStateFlags GetDynamicStateFlags(const array_view<const DynamicStateEnum> dynamicStates)
112 {
113 DynamicStateFlags flags = 0;
114 for (const auto& ref : dynamicStates) {
115 switch (ref) {
116 case CORE_DYNAMIC_STATE_ENUM_VIEWPORT:
117 flags |= CORE_DYNAMIC_STATE_VIEWPORT;
118 break;
119 case CORE_DYNAMIC_STATE_ENUM_SCISSOR:
120 flags |= CORE_DYNAMIC_STATE_SCISSOR;
121 break;
122 case CORE_DYNAMIC_STATE_ENUM_LINE_WIDTH:
123 flags |= CORE_DYNAMIC_STATE_LINE_WIDTH;
124 break;
125 case CORE_DYNAMIC_STATE_ENUM_DEPTH_BIAS:
126 flags |= CORE_DYNAMIC_STATE_DEPTH_BIAS;
127 break;
128 case CORE_DYNAMIC_STATE_ENUM_BLEND_CONSTANTS:
129 flags |= CORE_DYNAMIC_STATE_BLEND_CONSTANTS;
130 break;
131 case CORE_DYNAMIC_STATE_ENUM_DEPTH_BOUNDS:
132 flags |= CORE_DYNAMIC_STATE_DEPTH_BOUNDS;
133 break;
134 case CORE_DYNAMIC_STATE_ENUM_STENCIL_COMPARE_MASK:
135 flags |= CORE_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
136 break;
137 case CORE_DYNAMIC_STATE_ENUM_STENCIL_WRITE_MASK:
138 flags |= CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK;
139 break;
140 case CORE_DYNAMIC_STATE_ENUM_STENCIL_REFERENCE:
141 flags |= CORE_DYNAMIC_STATE_STENCIL_REFERENCE;
142 break;
143 default:
144 break;
145 }
146 }
147 return flags;
148 }
149
HighestBit(uint32_t value)150 uint32_t HighestBit(uint32_t value)
151 {
152 uint32_t count = 0;
153 while (value) {
154 ++count;
155 value >>= 1U;
156 }
157 return count;
158 }
159 } // namespace
160
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)161 GraphicsPipelineStateObjectGLES::GraphicsPipelineStateObjectGLES(Device& device,
162 const GpuShaderProgram& gpuShaderProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
163 const VertexInputDeclarationView& vertexInputDeclaration,
164 const ShaderSpecializationConstantDataView& specializationConstants,
165 const array_view<const DynamicStateEnum> dynamicStates, const RenderPassDesc& renderPassDesc,
166 const array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs)
167 : GraphicsPipelineStateObject(), device_((DeviceGLES&)device)
168 {
169 plat_.graphicsState = graphicsState;
170 plat_.pipelineLayout = pipelineLayout;
171 for (const auto& t : vertexInputDeclaration.attributeDescriptions) {
172 plat_.vertexInputDeclaration.attributeDescriptions[plat_.vertexInputDeclaration.attributeDescriptionCount] = t;
173 plat_.vertexInputDeclaration.attributeDescriptionCount++;
174 }
175 for (const auto& t : vertexInputDeclaration.bindingDescriptions) {
176 plat_.vertexInputDeclaration.bindingDescriptions[plat_.vertexInputDeclaration.bindingDescriptionCount] = t;
177 plat_.vertexInputDeclaration.bindingDescriptionCount++;
178 }
179 plat_.renderPassDesc = renderPassDesc;
180 plat_.dynamicStateFlags = GetDynamicStateFlags(dynamicStates);
181
182 const auto& source = static_cast<const GpuShaderProgramGLES&>(gpuShaderProgram);
183
184 uint32_t views = 0U;
185 for (const auto& subpass : renderPassSubpassDescs) {
186 views = Math::max(HighestBit(subpass.viewMask), views);
187 }
188 plat_.views = views;
189
190 specialized_ = source.Specialize(specializationConstants, views);
191 plat_.graphicsShader = specialized_.get();
192 if (plat_.graphicsShader) {
193 MakeVAO();
194 }
195 }
196
GetOESProgram(array_view<const OES_Bind> oesBinds) const197 GpuShaderProgramGLES* GraphicsPipelineStateObjectGLES::GetOESProgram(array_view<const OES_Bind> oesBinds) const
198 {
199 BASE_NS::string key;
200 for (auto& bind : oesBinds) {
201 key += BASE_NS::to_string(bind.set);
202 key += '_';
203 key += BASE_NS::to_string(bind.bind);
204 key += '_';
205 }
206 if (auto it = oesPrograms_.find(key); it != oesPrograms_.end()) {
207 // return existing.
208 return it->second.get();
209 }
210 // create new one.
211 return oesPrograms_.insert({ key, specialized_->OesPatch(oesBinds, plat_.views) }).first->second.get();
212 }
213
MakeVAO()214 void GraphicsPipelineStateObjectGLES::MakeVAO() noexcept
215 {
216 PLUGIN_ASSERT(device_.IsActive());
217 if (plat_.vao != 0) {
218 return; // early out
219 }
220 const auto& shaderdata = (const GpuShaderProgramPlatformDataGL&)plat_.graphicsShader->GetPlatformData();
221 PLUGIN_ASSERT(shaderdata.program != 0);
222 const uint32_t curVAO = device_.BoundVertexArray();
223 plat_.vao = device_.CreateVertexArray();
224 device_.BindVertexArray(plat_.vao);
225 const VertexInputDeclarationData& vertexInputDecl = plat_.vertexInputDeclaration;
226 for (size_t idx = 0; idx < vertexInputDecl.attributeDescriptionCount; ++idx) {
227 if (shaderdata.inputs[idx] != Gles::INVALID_LOCATION) {
228 const auto& attributeRef = vertexInputDecl.attributeDescriptions[idx];
229 GLuint count = 2;
230 GLenum type = GL_FLOAT;
231 GLboolean normalized = false;
232 bool isFloat = false;
233 FormatToVertexType(attributeRef, count, type, normalized, isFloat);
234 glEnableVertexAttribArray((GLuint)idx);
235 glVertexAttribBinding((GLuint)idx, attributeRef.binding);
236 if (isFloat) {
237 glVertexAttribFormat((GLuint)idx, (GLint)count, type, normalized, (GLuint)attributeRef.offset);
238 } else {
239 glVertexAttribIFormat((GLuint)idx, (GLint)count, type, (GLuint)attributeRef.offset);
240 }
241 } else {
242 glDisableVertexAttribArray((GLuint)idx);
243 }
244 }
245 device_.BindVertexArray(curVAO);
246 }
247
~GraphicsPipelineStateObjectGLES()248 GraphicsPipelineStateObjectGLES::~GraphicsPipelineStateObjectGLES()
249 {
250 if (plat_.vao) {
251 PLUGIN_ASSERT(device_.IsActive());
252 device_.DeleteVertexArray(plat_.vao);
253 }
254 }
255
GetPlatformData() const256 const PipelineStateObjectPlatformDataGL& GraphicsPipelineStateObjectGLES::GetPlatformData() const
257 {
258 return plat_;
259 }
260
ComputePipelineStateObjectGLES(Device & device,const GpuComputeProgram & gpuComputeProgram,const PipelineLayout & pipelineLayout,const ShaderSpecializationConstantDataView & specializationConstants)261 ComputePipelineStateObjectGLES::ComputePipelineStateObjectGLES(Device& device,
262 const GpuComputeProgram& gpuComputeProgram, const PipelineLayout& pipelineLayout,
263 const ShaderSpecializationConstantDataView& specializationConstants)
264 : ComputePipelineStateObject(), device_((DeviceGLES&)device)
265 {
266 PLUGIN_UNUSED(device_);
267 plat_.pipelineLayout = pipelineLayout;
268 const auto& source = static_cast<const GpuComputeProgramGLES&>(gpuComputeProgram);
269 specialized_ = source.Specialize(specializationConstants);
270 plat_.computeShader = specialized_.get();
271 }
272
273 ComputePipelineStateObjectGLES::~ComputePipelineStateObjectGLES() = default;
274
GetPlatformData() const275 const PipelineStateObjectPlatformDataGL& ComputePipelineStateObjectGLES::GetPlatformData() const
276 {
277 return plat_;
278 }
279 RENDER_END_NAMESPACE()
280