• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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