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#ifndef GLES_DEVICE_GLES_H
17#define GLES_DEVICE_GLES_H
18
19#include <cstddef>
20#include <cstdint>
21#include <mutex>
22
23#include <base/containers/string_view.h>
24#include <base/containers/unique_ptr.h>
25#include <base/containers/vector.h>
26#include <base/math/vector.h>
27#include <base/namespace.h>
28#include <render/device/pipeline_state_desc.h>
29#include <render/gles/intf_device_gles.h>
30#include <render/namespace.h>
31#include <render/resource_handle.h>
32
33#include "device/device.h"
34#include "gles/swapchain_gles.h"
35
36#if RENDER_HAS_GLES_BACKEND
37#include "egl_state.h"
38#endif
39#if RENDER_HAS_GL_BACKEND
40#include "wgl_state.h"
41#endif
42
43RENDER_BEGIN_NAMESPACE()
44class ComputePipelineStateObject;
45class GpuBuffer;
46class GpuComputeProgram;
47class GpuImage;
48class GpuResourceManager;
49class GpuSemaphore;
50class GpuSampler;
51class GpuShaderProgram;
52class GraphicsPipelineStateObject;
53class LowLevelDeviceGLES;
54class NodeContextDescriptorSetManager;
55class NodeContextPoolManager;
56class RenderBackend;
57class RenderFrameSync;
58class PlatformGpuMemoryAllocator;
59class ShaderManager;
60class Swapchain;
61class SwapchainGLES;
62
63struct BackendSpecificImageDesc;
64struct GpuAccelerationStructureDesc;
65struct GpuBufferDesc;
66struct GpuComputeProgramCreateData;
67struct GpuImageDesc;
68struct GpuImagePlatformData;
69struct GpuSamplerDesc;
70struct GpuShaderProgramCreateData;
71struct SwapchainCreateInfo;
72struct PipelineLayout;
73
74class DeviceGLES final : public Device {
75public:
76    // NOTE: normalized flag
77    struct ImageFormat {
78        BASE_NS::Format coreFormat;
79        uint32_t format;
80        uint32_t internalFormat;
81        uint32_t dataType;
82        uint32_t bytesperpixel;
83        struct {
84            bool compressed;
85            uint8_t blockW;
86            uint8_t blockH;
87            uint32_t bytesperblock;
88        } compression;
89        BASE_NS::Math::UVec4 swizzle;
90    };
91
92    DeviceGLES(RenderContext& renderContext, DeviceCreateInfo const& createInfo);
93    ~DeviceGLES() override;
94
95    // From IDevice
96    DeviceBackendType GetBackendType() const override;
97    const DevicePlatformData& GetPlatformData() const override;
98    AccelerationStructureBuildSizes GetAccelerationStructureBuildSizes(
99        const AccelerationStructureBuildGeometryInfo& geometry,
100        BASE_NS::array_view<const AccelerationStructureGeometryTrianglesInfo> triangles,
101        BASE_NS::array_view<const AccelerationStructureGeometryAabbsInfo> aabbs,
102        BASE_NS::array_view<const AccelerationStructureGeometryInstancesInfo> instances) const override;
103    FormatProperties GetFormatProperties(BASE_NS::Format format) const override;
104    ILowLevelDevice& GetLowLevelDevice() const override;
105    // NOTE: can be called from API
106    void WaitForIdle() override;
107
108    PlatformGpuMemoryAllocator* GetPlatformGpuMemoryAllocator() override;
109
110    // (re-)create swapchain
111    BASE_NS::unique_ptr<Swapchain> CreateDeviceSwapchain(const SwapchainCreateInfo& swapchainCreateInfo) override;
112    void DestroyDeviceSwapchain() override;
113
114    bool IsActive() const;
115    void Activate() override;
116    void Deactivate() override;
117
118    bool AllowThreadedProcessing() const override;
119
120    GpuQueue GetValidGpuQueue(const GpuQueue& gpuQueue) const override;
121    uint32_t GetGpuQueueCount() const override;
122
123    void InitializePipelineCache(BASE_NS::array_view<const uint8_t> initialData) override;
124    BASE_NS::vector<uint8_t> GetPipelineCache() const override;
125
126    BASE_NS::unique_ptr<GpuBuffer> CreateGpuBuffer(const GpuBufferDesc& desc) override;
127    BASE_NS::unique_ptr<GpuBuffer> CreateGpuBuffer(const GpuAccelerationStructureDesc& desc) override;
128
129    // Create gpu image resources
130    BASE_NS::unique_ptr<GpuImage> CreateGpuImage(const GpuImageDesc& desc) override;
131    BASE_NS::unique_ptr<GpuImage> CreateGpuImageView(
132        const GpuImageDesc& desc, const GpuImagePlatformData& platformData) override;
133    BASE_NS::unique_ptr<GpuImage> CreateGpuImageView(
134        const GpuImageDesc& desc, const BackendSpecificImageDesc& platformData) override;
135    BASE_NS::vector<BASE_NS::unique_ptr<GpuImage>> CreateGpuImageViews(const Swapchain& platformSwapchain) override;
136
137    BASE_NS::unique_ptr<GpuSampler> CreateGpuSampler(const GpuSamplerDesc& desc) override;
138
139    BASE_NS::unique_ptr<RenderFrameSync> CreateRenderFrameSync() override;
140
141    BASE_NS::unique_ptr<RenderBackend> CreateRenderBackend(
142        GpuResourceManager& gpuResourceMgr, const CORE_NS::IParallelTaskQueue::Ptr& queue) override;
143
144    BASE_NS::unique_ptr<ShaderModule> CreateShaderModule(const ShaderModuleCreateInfo& data) override;
145    BASE_NS::unique_ptr<ShaderModule> CreateComputeShaderModule(const ShaderModuleCreateInfo& data) override;
146    BASE_NS::unique_ptr<GpuShaderProgram> CreateGpuShaderProgram(const GpuShaderProgramCreateData& data) override;
147    BASE_NS::unique_ptr<GpuComputeProgram> CreateGpuComputeProgram(const GpuComputeProgramCreateData& data) override;
148
149    BASE_NS::unique_ptr<NodeContextDescriptorSetManager> CreateNodeContextDescriptorSetManager() override;
150    BASE_NS::unique_ptr<NodeContextPoolManager> CreateNodeContextPoolManager(
151        class GpuResourceManager& gpuResourceMgr, const GpuQueue& gpuQueue) override;
152
153    BASE_NS::unique_ptr<GraphicsPipelineStateObject> CreateGraphicsPipelineStateObject(
154        const GpuShaderProgram& gpuProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
155        const VertexInputDeclarationView& vertexInputDeclaration,
156        const ShaderSpecializationConstantDataView& specializationConstants,
157        const BASE_NS::array_view<const DynamicStateEnum> dynamicStates, const RenderPassDesc& renderPassDesc,
158        const BASE_NS::array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs, const uint32_t subpassIndex,
159        const LowLevelRenderPassData* renderPassData, const LowLevelPipelineLayoutData* pipelineLayoutData) override;
160
161    BASE_NS::unique_ptr<ComputePipelineStateObject> CreateComputePipelineStateObject(
162        const GpuComputeProgram& gpuProgram, const PipelineLayout& pipelineLayout,
163        const ShaderSpecializationConstantDataView& specializationConstants,
164        const LowLevelPipelineLayoutData* pipelineLayoutData) override;
165
166    BASE_NS::unique_ptr<GpuSemaphore> CreateGpuSemaphore() override;
167    BASE_NS::unique_ptr<GpuSemaphore> CreateGpuSemaphoreView(const uint64_t handle) override;
168
169    void SetBackendConfig(const BackendConfig& config) override;
170
171    // Internal apis, only usable by other parts of GLES backend.
172    bool HasExtension(BASE_NS::string_view extension) const;
173    void Activate(RenderHandle swapchain);
174#if RENDER_HAS_GL_BACKEND
175    const WGLHelpers::WGLState& GetEglState();
176#endif
177#if RENDER_HAS_GLES_BACKEND
178    const EGLHelpers::EGLState& GetEglState();
179    bool IsDepthResolveSupported() const;
180#endif
181
182    uint32_t CacheProgram(
183        BASE_NS::string_view vertSource, BASE_NS::string_view fragSource, BASE_NS::string_view compSource);
184    void ReleaseProgram(uint32_t program);
185
186    void UseProgram(uint32_t program);
187    void BindBuffer(uint32_t target, uint32_t buffer);
188    void BindBufferRange(uint32_t target, uint32_t binding, uint32_t buffer, uint64_t offset, uint64_t size);
189    void BindSampler(uint32_t textureUnit, uint32_t sampler);
190    void BindTexture(uint32_t textureUnit, uint32_t target, uint32_t texture); // target = GL_TEXTURE_2D et al.
191    void BindImageTexture(uint32_t unit, uint32_t texture, uint32_t level, bool layered, uint32_t layer,
192        uint32_t access, uint32_t format);
193    void BindFrameBuffer(uint32_t fbo);
194    void BindReadFrameBuffer(uint32_t fbo);
195    void BindWriteFrameBuffer(uint32_t fbo);
196    void BindVertexArray(uint32_t vao);
197
198    void BindVertexBuffer(uint32_t slot, uint32_t buffer, intptr_t offset, intptr_t stride);
199    void VertexBindingDivisor(uint32_t slot, uint32_t divisor);
200    void BindElementBuffer(uint32_t buffer);
201
202    uint32_t BoundReadFrameBuffer() const;
203    uint32_t BoundWriteFrameBuffer() const;
204
205    uint32_t BoundProgram() const;
206    uint32_t BoundBuffer(uint32_t target) const;
207    uint32_t BoundBuffer(uint32_t target, uint32_t binding) const;
208    uint32_t BoundSampler(uint32_t textureUnit) const;
209    uint32_t BoundTexture(uint32_t textureUnit, uint32_t target) const;
210    uint32_t BoundVertexArray() const;
211
212    // Creation functions for objects.
213    uint32_t CreateVertexArray();
214    // Deletion functions for objects.
215    void DeleteTexture(uint32_t texture);
216    void DeleteBuffer(uint32_t buffer);
217    void DeleteSampler(uint32_t sampler);
218    void DeleteVertexArray(uint32_t vao);
219    void DeleteFrameBuffer(uint32_t fbo);
220
221    void SetActiveTextureUnit(uint32_t textureUnit); // hide this.
222    // swizzles for textures
223    void TexSwizzle(uint32_t image, uint32_t target, const BASE_NS::Math::UVec4& swizzle);
224    // texture upload / storage
225    void TexStorage2D(
226        uint32_t image, uint32_t target, uint32_t levels, uint32_t internalformat, const BASE_NS::Math::UVec2& extent);
227    void TexStorage3D(
228        uint32_t image, uint32_t target, uint32_t levels, uint32_t internalformat, const BASE_NS::Math::UVec3& extent);
229    void TexStorage2DMultisample(uint32_t image, uint32_t target, uint32_t samples, uint32_t internalformat,
230        const BASE_NS::Math::UVec2& extent, bool fixedsamplelocations);
231
232    void TexSubImage2D(uint32_t image, uint32_t target, uint32_t level, const BASE_NS::Math::UVec2& offset,
233        const BASE_NS::Math::UVec2& extent, uint32_t format, uint32_t type, const void* pixels);
234    void TexSubImage3D(uint32_t image, uint32_t target, uint32_t level, const BASE_NS::Math::UVec3& offset,
235        const BASE_NS::Math::UVec3& extent, uint32_t format, uint32_t type, const void* pixels);
236    void CompressedTexSubImage2D(uint32_t image, uint32_t target, uint32_t level, const BASE_NS::Math::UVec2& offset,
237        const BASE_NS::Math::UVec2& extent, uint32_t format, uint32_t imageSize, const void* data);
238    void CompressedTexSubImage3D(uint32_t image, uint32_t target, uint32_t level, const BASE_NS::Math::UVec3& offset,
239        const BASE_NS::Math::UVec3& extent, uint32_t format, uint32_t imageSize, const void* data);
240
241    const ImageFormat& GetGlImageFormat(BASE_NS::Format format) const;
242
243    void SwapBuffers(const SwapchainGLES&);
244
245private:
246    enum BufferBindId : uint32_t {
247        UNIFORM_BUFFER_BIND = 0,
248        SHADER_STORAGE_BUFFER_BIND,
249#ifdef HANDLE_UNSUPPORTED_ENUMS
250        ATOMIC_COUNTER_BUFFER_BIND,
251        TRANSFORM_FEEDBACK_BUFFER_BIND,
252#endif
253        MAX_BUFFER_BIND_ID
254    };
255
256    enum BufferTargetId : uint32_t {
257        PIXEL_UNPACK_BUFFER = 0,
258        PIXEL_PACK_BUFFER,
259        COPY_READ_BUFFER,
260        COPY_WRITE_BUFFER,
261        UNIFORM_BUFFER,
262        SHADER_STORAGE_BUFFER,
263        DISPATCH_INDIRECT_BUFFER,
264        DRAW_INDIRECT_BUFFER,
265#ifdef HANDLE_UNSUPPORTED_ENUMS
266        ATOMIC_COUNTER_BUFFER,
267        QUERY_BUFFER,
268        TRANSFORM_FEEDBACK_BUFFER,
269        ARRAY_BUFFER,
270        ELEMENT_ARRAY_BUFFER, // stored in VAO state...
271        TEXTURE_BUFFER,
272#endif
273        MAX_BUFFER_TARGET_ID
274    };
275
276    enum TextureTargetId : uint32_t {
277        TEXTURE_2D = 0,
278        TEXTURE_CUBE_MAP = 1,
279#if RENDER_HAS_GLES_BACKEND
280        TEXTURE_EXTERNAL_OES = 2,
281#endif
282        TEXTURE_2D_MULTISAMPLE = 3,
283        TEXTURE_2D_ARRAY = 4,
284        TEXTURE_3D = 5,
285        MAX_TEXTURE_TARGET_ID
286    };
287
288    static constexpr uint32_t READ_ONLY { 0x88B8 }; /* GL_READ_ONLY */
289    static constexpr uint32_t R32UI { 0x8236 };     /* GL_R32UI */
290    static constexpr uint32_t MAX_TEXTURE_UNITS { 16 };
291    static constexpr uint32_t MAX_SAMPLERS { 16 };
292    static constexpr uint32_t MAX_BOUND_IMAGE { 16 };
293    static constexpr uint32_t MAX_BINDING_VALUE { 16 };
294
295    // Cleanup cache state when deleting objects.
296    void UnBindTexture(uint32_t texture);
297    void UnBindBuffer(uint32_t buffer);
298    void UnBindBufferFromVertexArray(uint32_t buffer);
299    void UnBindSampler(uint32_t sampler);
300    void UnBindVertexArray(uint32_t vao);
301    void UnBindFrameBuffer(uint32_t fbo);
302
303    BASE_NS::vector<BASE_NS::string_view> extensions_;
304    BASE_NS::vector<ImageFormat> supportedFormats_;
305
306    enum { VERTEX_CACHE = 0, FRAGMENT_CACHE = 1, COMPUTE_CACHE = 2, MAX_CACHES };
307    struct ShaderCache {
308        size_t hit { 0 };
309        size_t miss { 0 };
310        struct Entry {
311            uint32_t shader { 0 };
312            uint64_t hash { 0 }; // hash of generated GLSL
313            uint32_t refCount { 0 };
314        };
315        BASE_NS::vector<Entry> cache;
316    };
317    ShaderCache caches[MAX_CACHES];
318
319    const ShaderCache::Entry& CacheShader(int type, BASE_NS::string_view source);
320    void ReleaseShader(uint32_t type, uint32_t shader);
321
322    struct ProgramCache {
323        uint32_t program { 0 };
324        uint32_t vertShader { 0 };
325        uint32_t fragShader { 0 };
326        uint32_t compShader { 0 };
327        uint64_t hashVert { 0 };
328        uint64_t hashFrag { 0 };
329        uint64_t hashComp { 0 };
330        uint32_t refCount { 0 };
331    };
332    BASE_NS::vector<ProgramCache> programs_;
333    size_t pCacheHit_ { 0 };
334    size_t pCacheMiss_ { 0 };
335
336#if RENDER_HAS_GL_BACKEND
337#if _WIN32
338    const DeviceBackendType backendType_ = DeviceBackendType::OPENGL;
339    WGLHelpers::WGLState eglState_;
340#else
341#error Core::DeviceBackendType::OPENGL not implemented for this platform yet.
342#endif
343#endif
344#if RENDER_HAS_GLES_BACKEND
345    const DeviceBackendType backendType_ = DeviceBackendType::OPENGLES;
346    EGLHelpers::EGLState eglState_;
347    BackendConfigGLES backendConfig_ { {}, false };
348#endif
349    mutable std::mutex activeMutex_;
350    uint32_t isActive_ { 0 };
351    bool isRenderbackendRunning_ { false };
352    BASE_NS::unique_ptr<LowLevelDeviceGLES> lowLevelDevice_;
353    // GL State cache..
354    // cache.
355    uint32_t activeTextureUnit_ = { 0 };
356    uint32_t boundSampler_[MAX_SAMPLERS] = { 0 };
357
358    struct {
359        bool bound { false };
360        uint32_t texture { 0 };
361        uint32_t level { 0 };
362        bool layered { false };
363        uint32_t layer { 0 };
364        uint32_t access { READ_ONLY };
365        uint32_t format { R32UI };
366    } boundImage_[MAX_BOUND_IMAGE] = { {} };
367
368    uint32_t boundTexture_[MAX_TEXTURE_UNITS][MAX_TEXTURE_TARGET_ID] = { { 0 } }; // [textureunit][target type]
369
370    struct BufferCache {
371        bool cached { false };
372        uint32_t buffer { 0 };
373        uint64_t offset { 0 };
374        uint64_t size { 0 };
375    };
376    // Cache for GL_ATOMIC_COUNTER_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM_BUFFER, or GL_SHADER_STORAGE_BUFFER
377    // bindings.
378    BufferCache boundBuffers_[MAX_BUFFER_BIND_ID][MAX_BINDING_VALUE] = { {} };
379
380    // bufferBound_ caches GL_PIXEL_UNPACK_BUFFER / GL_COPY_READ_BUFFER / GL_COPY_WRITE_BUFFER (and other generic
381    // bindings)
382    struct {
383        bool bound { false };
384        uint32_t buffer { 0 };
385    } bufferBound_[MAX_BUFFER_TARGET_ID];
386    uint32_t boundReadFbo_ { 0 };
387    uint32_t boundWriteFbo_ { 0 };
388    uint32_t boundVao_ { 0 };
389    uint32_t boundProgram_ { 0 };
390    struct VAOState {
391        uint32_t vao { 0 }; // GL name for object.
392        struct {
393            bool bound { false };
394            uint32_t buffer { 0 };
395        } elementBuffer;
396        struct {
397            bool bound { false };
398            uint32_t buffer { 0 };
399            intptr_t offset { 0 };
400            intptr_t stride { 0 };
401            uint32_t divisor { 0 };
402        } vertexBufferBinds[PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
403    };
404    BASE_NS::vector<VAOState> vaoStates_;
405    size_t vaoStatesInUse_ = 0;
406
407    // glid -> internal id
408    static BufferBindId IndexedTargetToTargetId(uint32_t target);
409    static uint32_t TargetToBinding(uint32_t target);
410    static BufferTargetId GenericTargetToTargetId(uint32_t target);
411    static TextureTargetId TextureTargetToTargetId(uint32_t target);
412
413    // internal id -> glid
414    static uint32_t GenericTargetIdToTarget(BufferTargetId target);
415    static uint32_t IndexedTargetIdToTarget(BufferBindId target);
416    static uint32_t TextureTargetIdToTarget(TextureTargetId target);
417};
418
419// Wrapper for low level device access
420class LowLevelDeviceGLES final : public ILowLevelDeviceGLES {
421public:
422    explicit LowLevelDeviceGLES(DeviceGLES& deviceGLES);
423    ~LowLevelDeviceGLES() = default;
424
425    DeviceBackendType GetBackendType() const override;
426
427#if RENDER_HAS_EXPERIMENTAL
428    void Activate() override;
429    void Deactivate() override;
430    void SwapBuffers() override;
431#endif
432
433private:
434    DeviceGLES& deviceGLES_;
435    GpuResourceManager& gpuResourceMgr_;
436};
437
438#if (RENDER_HAS_GL_BACKEND)
439BASE_NS::unique_ptr<Device> CreateDeviceGL(RenderContext& renderContext, DeviceCreateInfo const& createInfo);
440#endif
441#if (RENDER_HAS_GLES_BACKEND)
442BASE_NS::unique_ptr<Device> CreateDeviceGLES(RenderContext& renderContext, DeviceCreateInfo const& createInfo);
443#endif
444RENDER_END_NAMESPACE()
445
446#endif // GLES_DEVICE_GLES_H
447