From b523c5c236660a21a194d4869e40a91414e32351 Mon Sep 17 00:00:00 2001 From: zach Date: Thu, 27 Jul 2023 17:21:41 +0800 Subject: [PATCH 1/2] [refactoring]gfx egl. --- native/CMakeLists.txt | 25 ++- native/cocos/base/DynamicLibrary.cpp | 50 +++++ native/cocos/base/DynamicLibrary.h | 30 +++ .../platform/java/modules/XRInterface.cpp | 2 +- .../common/GLESCommandStorage.cpp | 61 ++++++ .../common/GLESCommandStorage.h | 76 +++++++ .../gfx-gles-common/common/GLESQueue.cpp | 56 +++++ .../gfx-gles-common/common/GLESQueue.h | 66 ++++++ .../cocos/renderer/gfx-gles-common/egl/Base.h | 36 ++++ .../renderer/gfx-gles-common/egl/Context.cpp | 192 ++++++++++++++++++ .../renderer/gfx-gles-common/egl/Context.h | 58 ++++++ .../renderer/gfx-gles-common/egl/Instance.cpp | 166 +++++++++++++++ .../renderer/gfx-gles-common/egl/Instance.h | 35 ++++ .../renderer/gfx-gles-common/egl/Surface.cpp | 19 ++ .../renderer/gfx-gles-common/egl/Surface.h | 48 +++++ .../gfx-gles-common/{ => loader}/eglw.cpp | 0 .../gfx-gles-common/{ => loader}/eglw.h | 0 .../gfx-gles-common/{ => loader}/gles2w.cpp | 0 .../gfx-gles-common/{ => loader}/gles2w.h | 0 .../gfx-gles-common/{ => loader}/gles3w.cpp | 0 .../gfx-gles-common/{ => loader}/gles3w.h | 0 .../cocos/renderer/gfx-gles2/GLES2Wrangler.h | 4 +- .../cocos/renderer/gfx-gles3/GLES3Wrangler.h | 6 +- 23 files changed, 919 insertions(+), 11 deletions(-) create mode 100644 native/cocos/base/DynamicLibrary.cpp create mode 100644 native/cocos/base/DynamicLibrary.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESQueue.h create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Base.h create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Context.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Context.h create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Instance.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Instance.h create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Surface.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Surface.h rename native/cocos/renderer/gfx-gles-common/{ => loader}/eglw.cpp (100%) rename native/cocos/renderer/gfx-gles-common/{ => loader}/eglw.h (100%) rename native/cocos/renderer/gfx-gles-common/{ => loader}/gles2w.cpp (100%) rename native/cocos/renderer/gfx-gles-common/{ => loader}/gles2w.h (100%) rename native/cocos/renderer/gfx-gles-common/{ => loader}/gles3w.cpp (100%) rename native/cocos/renderer/gfx-gles-common/{ => loader}/gles3w.h (100%) diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index a1c3dacce9b..7512550daa2 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -461,6 +461,8 @@ cocos_source_files( cocos/base/TypeDef.h cocos/base/BinaryArchive.cpp cocos/base/BinaryArchive.h + cocos/base/DynamicLibrary.cpp + cocos/base/DynamicLibrary.h cocos/base/std/any.h cocos/base/std/optional.h cocos/base/std/variant.h @@ -1612,14 +1614,27 @@ cocos_source_files( # ) if(CC_USE_GLES2 OR CC_USE_GLES3) + cocos_source_files( + cocos/renderer/gfx-gles-common/common/GLESQueue.cpp + cocos/renderer/gfx-gles-common/common/GLESQueue.h + cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp + cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h + cocos/renderer/gfx-gles-common/egl/Context.cpp + cocos/renderer/gfx-gles-common/egl/Context.h + cocos/renderer/gfx-gles-common/egl/Surface.cpp + cocos/renderer/gfx-gles-common/egl/Surface.h + cocos/renderer/gfx-gles-common/egl/Instance.cpp + cocos/renderer/gfx-gles-common/egl/Instance.h + ) + cocos_source_files( cocos/renderer/gfx-gles-common/GLESCommandPool.h - cocos/renderer/gfx-gles-common/eglw.cpp - cocos/renderer/gfx-gles-common/gles2w.cpp + cocos/renderer/gfx-gles-common/loader/eglw.cpp + cocos/renderer/gfx-gles-common/loader/gles2w.cpp ) if(CC_USE_GLES3) cocos_source_files( - cocos/renderer/gfx-gles-common/gles3w.cpp + cocos/renderer/gfx-gles-common/loader/gles3w.cpp ) endif() endif() @@ -2374,7 +2389,7 @@ if(USE_MIDDLEWARE) NO_WERROR cocos/editor-support/spine-creator-support/spine-cocos2dx.cpp cocos/editor-support/spine-creator-support/spine-cocos2dx.h NO_WERROR cocos/editor-support/spine-creator-support/VertexEffectDelegate.cpp - cocos/editor-support/spine-creator-support/VertexEffectDelegate.h + cocos/editor-support/spine-creator-support/VertexEffectDelegate.h ) cocos_source_files( @@ -3327,7 +3342,7 @@ set(COCOS_SOURCE_LIST_EXCLUDE_GENRATED ${COCOS_SOURCE_LIST}) set(COCOS_GENERATED_LIST) foreach(src IN LISTS COCOS_SOURCE_LIST_EXCLUDE_GENRATED) get_source_file_property(IS_GENERATED ${src} GENERATED) - if(IS_GENERATED) + if(IS_GENERATED) list(REMOVE_ITEM COCOS_SOURCE_LIST_EXCLUDE_GENRATED ${src}) list(APPEND COCOS_GENERATED_LIST ${src}) endif() diff --git a/native/cocos/base/DynamicLibrary.cpp b/native/cocos/base/DynamicLibrary.cpp new file mode 100644 index 00000000000..f6df490a8ca --- /dev/null +++ b/native/cocos/base/DynamicLibrary.cpp @@ -0,0 +1,50 @@ +#include "DynamicLibrary.h" + +namespace cc { + +DynamicLibrary::~DynamicLibrary() { + unload(); +} + +bool DynamicLibrary::load() { +#ifdef _WIN32 + _handle = ::LoadLibraryExA(_libName.c_str(), nullptr, 0); +#elif defined(__EMSCRIPTEN__) + _handle = nullptr; +#else + _handle = dlopen(_libName.c_str(), RTLD_LOCAL | RTLD_LAZY); +#endif + return _handle != nullptr; +} + +void DynamicLibrary::unload() { + if (_handle != nullptr) { +#ifdef _WIN32 + ::FreeLibrary(static_cast(_handle)); +#elif defined(__EMSCRIPTEN__) + // do nothing +#else + dlclose(_handle); +#endif + _handle = nullptr; + } +} + +bool DynamicLibrary::isLoaded() const { + return _handle != nullptr; +} + +void* DynamicLibrary::getProcAddress(const std::string &key) const { + if (_handle == nullptr) { + return nullptr; + } +#ifdef _WIN32 + return reinterpret_cast(::GetProcAddress(static_cast(_handle), key.c_str())); +#elif defined(__EMSCRIPTEN__) + return nullptr; +#else + return dlsym(_handle, key.c_str()); +#endif +} + +} // namespace cc diff --git a/native/cocos/base/DynamicLibrary.h b/native/cocos/base/DynamicLibrary.h new file mode 100644 index 00000000000..04e2a9152a5 --- /dev/null +++ b/native/cocos/base/DynamicLibrary.h @@ -0,0 +1,30 @@ +#pragma once + +#include "base/std/container/string.h" + +#ifdef _WIN32 + #include +#else + #include +#endif + + +namespace cc { + +class DynamicLibrary { +public: + explicit DynamicLibrary(ccstd::string name) : _libName(std::move(name)) {} + ~DynamicLibrary(); + + bool load(); + void unload(); + bool isLoaded() const; + + void* getProcAddress(const std::string &key) const; + +private: + std::string _libName; + void *_handle = nullptr; +}; + +} // namespace cc diff --git a/native/cocos/platform/java/modules/XRInterface.cpp b/native/cocos/platform/java/modules/XRInterface.cpp index a9995cbfe55..f4d04117686 100644 --- a/native/cocos/platform/java/modules/XRInterface.cpp +++ b/native/cocos/platform/java/modules/XRInterface.cpp @@ -45,7 +45,7 @@ #include "gfx-vulkan/VKDevice.h" #endif #ifdef CC_USE_GLES3 - #include "gfx-gles-common/gles3w.h" + #include "gfx-gles-common/loader/gles3w.h" #include "gfx-gles3/GLES3Device.h" #include "renderer/gfx-gles3/GLES3GPUObjects.h" #endif diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp new file mode 100644 index 00000000000..0e773f2b3de --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp @@ -0,0 +1,61 @@ +#include "GLESCommandStorage.h" +#include "base/Utils.h" + +namespace cc::gfx { + +uint8_t *GLESCommandStorage::BlockStorage::allocate(uint32_t size, uint32_t alignment) { + auto alignSize = utils::alignTo(size, alignment); + if (!storage) { + storage = std::make_unique(blockSize); + } + + if (offset + alignSize > blockSize) { + return nullptr; + } + uint8_t *res = storage.get() + offset; + offset += size; + return res; +} + +void GLESCommandStorage::BlockStorage::reset() { + offset = 0; +} + +void GLESCommandStorage::allocateStorage() { + auto storage = std::make_unique(); + storage->offset = 0; + storage->blockSize = DEFAULT_BLOCK_SIZE; + _iterator = _storages.emplace(_iterator, std::move(storage)); +} + +void GLESCommandStorage::reset() { + for (auto &storage : _storages) { + storage->reset(); + } + _iterator = _storages.begin(); + _head = nullptr; + _current = &_head; +} + +void GLESCommandStorage::execute() { + while (_head != nullptr) { + auto *ptr = _head->next; + _head->execute(); + _head->~CmdBase(); + _head = ptr; + } +} + +uint8_t* GLESCommandStorage::allocate(uint32_t size, uint32_t alignment) { + uint8_t *ptr = (*_iterator)->allocate(size, alignment); + if (ptr == nullptr) { + _iterator++; + if (_iterator == _storages.end()) { + allocateStorage(); + } + ptr = (*_iterator)->allocate(size, alignment); + } + return ptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h new file mode 100644 index 00000000000..8d6b4199f9c --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +namespace cc::gfx { + +struct CmdBase { + CmdBase() = default; + virtual ~CmdBase() = default; + virtual void execute() {}; + CmdBase* next = nullptr; +}; + +template +struct Cmd : public CmdBase { + using Parameters = std::tuple...>; + using FuncType = Func; + + explicit Cmd(Func &&f, Args &&...args) : func(f), params(std::forward(args)...) {} + + FuncType func; + Parameters params; + + void execute() override { + std::apply(func, params); + } +}; + + +class GLESCommandStorage { +public: + GLESCommandStorage() = default; + ~GLESCommandStorage() = default; + + static constexpr uint32_t DEFAULT_ALIGNMENT = 4; + static constexpr uint32_t DEFAULT_BLOCK_SIZE = 1 * 1024 * 1024; // 1M + + uint8_t* allocate(uint32_t size, uint32_t alignment = DEFAULT_ALIGNMENT); + void reset(); + void execute(); + + template + void enqueueCmd(Func &&func, Args &&...args) + { + using CmdType = Cmd; + uint8_t *ptr = allocate(sizeof(CmdType)); + auto *cmd = new (ptr) CmdType(std::forward(func), std::forward(args)...); + + (*_current) = cmd; + _current = &(cmd->next); + } + + struct BlockStorage { + uint32_t blockSize = 0; + uint32_t offset = 0; + std::unique_ptr storage; + + uint8_t *allocate(uint32_t size, uint32_t alignment); + void reset(); + }; + +private: + void allocateStorage(); + + using StoragePtr = std::unique_ptr; + using Iterator = std::list::iterator; + + ccstd::list _storages; + Iterator _iterator = _storages.end(); + CmdBase* _head = nullptr; + CmdBase** _current = &_head; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp new file mode 100644 index 00000000000..6c052fae596 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp @@ -0,0 +1,56 @@ +#include "GLESQueue.h" + +namespace cc::gfx { + +bool GLESQueue::hasComplete(TaskHandle taskId) { + return _lastTaskId.load() >= taskId; +} + +void GLESQueue::wait(TaskHandle taskId) { + std::unique_lock lock(_mutex); + _taskCv.wait(lock, [=]() {return hasComplete(taskId); }); +} + +void GLESQueue::waitIdle() { + auto task = queueTask([](){}); + wait(task); +} + +void GLESQueue::threadMain() { + while (!_exit.load()) { + if (!runTask()) { + std::unique_lock lock(_mutex); + while (!_exit.load() && !hasTask()) { + _cv.wait(lock); + } + } + } +} + +bool GLESQueue::runTask() { + ccstd::vector tasks; + { + std::lock_guard const lock(_taskMutex); + if (_taskQueue.empty()) { + return false; + } + tasks.swap(_taskQueue); + } + for (auto &task : tasks) { + task.func(); + _lastTaskId.store(task.taskId); + { + std::unique_lock const lock(_mutex); + _taskCv.notify_all(); + } + } + + return true; +} + +bool GLESQueue::hasTask() { + std::lock_guard const lock(_taskMutex); + return !_taskQueue.empty(); +} + +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h new file mode 100644 index 00000000000..b007d4c4b49 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "base/std/container/vector.h" + +namespace cc::gfx { + +class GLESQueue { +public: + GLESQueue() = default; + virtual ~GLESQueue() = default; + + using TaskHandle = uint32_t; + + bool hasComplete(TaskHandle taskId); + void wait(TaskHandle taskId); + void waitIdle(); + + template + TaskHandle queueTask(T &&task) { + TaskHandle res = _taskCounter.fetch_add(1); + { + std::lock_guard const lock(_taskMutex); + _taskQueue.emplace_back(Task{res, std::forward(task)}); + } + { + std::lock_guard const lock(_mutex); + _cv.notify_all(); + } + return res; + } + +private: + friend class Device; + + struct Task { + TaskHandle taskId; + std::function func; + }; + + void threadMain(); + bool runTask(); + bool hasTask(); + + std::thread _thread; + + // thread mutex + std::mutex _mutex; + std::condition_variable _cv; + std::condition_variable _taskCv; + + // task queue mutex + std::mutex _taskMutex; + ccstd::vector _taskQueue; + + // status + std::atomic_bool _exit = false; + std::atomic _taskCounter = 0; + std::atomic _lastTaskId = 0; +}; + +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/egl/Base.h b/native/cocos/renderer/gfx-gles-common/egl/Base.h new file mode 100644 index 00000000000..c0f91c05994 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Base.h @@ -0,0 +1,36 @@ +#pragma once + +#include "base/Log.h" + +#include "gfx-gles-common/loader/eglw.h" +#include "gfx-gles-common/loader/gles2w.h" +#include "gfx-gles-common/loader/gles3w.h" + +#if CC_DEBUG > 0 + #define EGL_CHECK(x) \ + do { \ + x; \ + const EGLint err = eglGetError(); \ + if (err != EGL_SUCCESS) { \ + CC_LOG_ERROR("%s returned EGL error: 0x%x", #x, err); \ + CC_ABORT(); \ + } \ + } while (0) +#else + #define EGL_CHECK(x) x +#endif + +namespace cc::gfx::egl { + +struct Config { + EGLint red = 8; + EGLint green = 8; + EGLint blue = 8; + EGLint alpha = 8; + EGLint depth = 24; + EGLint stencil = 8; + EGLint sampleBuffers = 0; + EGLint sampleCount = 0; +}; + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Context.cpp b/native/cocos/renderer/gfx-gles-common/egl/Context.cpp new file mode 100644 index 00000000000..b41d363c197 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Context.cpp @@ -0,0 +1,192 @@ +#include "Context.h" +#include "gfx-gles-common/egl/Instance.h" + +namespace cc::gfx::egl { +namespace { +EGLConfig chooseConfig(EGLDisplay eglDisplay, const Config &cfg, bool qualityPreferred, bool msaaEnabled) { + EGLConfig eglConfig = EGL_NO_CONFIG_KHR; + + EGLint eglAttributes[]{ + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, + EGL_BLUE_SIZE, cfg.blue, + EGL_GREEN_SIZE, cfg.green, + EGL_RED_SIZE, cfg.blue, + EGL_ALPHA_SIZE, cfg.alpha, + EGL_DEPTH_SIZE, cfg.depth, + EGL_STENCIL_SIZE, cfg.stencil, + EGL_SAMPLE_BUFFERS, cfg.sampleBuffers, + EGL_SAMPLES, cfg.sampleCount, + EGL_NONE}; + + int numConfig{0}; + ccstd::vector eglConfigs; + auto success = eglChooseConfig(eglDisplay, eglAttributes, nullptr, 0, &numConfig); + if (success) { + eglConfigs.resize(numConfig); + } else { + CC_LOG_ERROR("Query GLES3 configuration failed."); + return eglConfig; + } + + int const count = numConfig; + EGL_CHECK(success = eglChooseConfig(eglDisplay, eglAttributes, eglConfigs.data(), numConfig, &numConfig)); + if (!success || !numConfig) { + CC_LOG_ERROR("eglChooseConfig configuration failed."); + return eglConfig; + } + + EGLint depth{0}; + EGLint stencil{0}; + EGLint sampleBuffers{0}; + EGLint sampleCount{0}; + EGLint params[8]{0}; + uint64_t lastScore = qualityPreferred ? std::numeric_limits::min() : std::numeric_limits::max(); + + for (int i = 0; i < numConfig; i++) { + int depthValue{0}; + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_RED_SIZE, ¶ms[0]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_GREEN_SIZE, ¶ms[1]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_BLUE_SIZE, ¶ms[2]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_ALPHA_SIZE, ¶ms[3]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_DEPTH_SIZE, ¶ms[4]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_STENCIL_SIZE, ¶ms[5]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_SAMPLE_BUFFERS, ¶ms[6]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_SAMPLES, ¶ms[7]); + eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_DEPTH_ENCODING_NV, &depthValue); + + int const bNonLinearDepth = (depthValue == EGL_DEPTH_ENCODING_NONLINEAR_NV) ? 1 : 0; + + /*------------------------------------------ANGLE's priority-----------------------------------------------*/ + // Favor EGLConfigLists by RGB, then Depth, then Non-linear Depth, then Stencil, then Alpha + uint64_t currScore{0}; + EGLint const colorScore = std::abs(params[0] - cfg.red) + std::abs(params[1] - cfg.green) + std::abs(params[2] - cfg.blue); + currScore |= static_cast(std::min(std::max(params[6], 0), 15)) << 29; + currScore |= static_cast(std::min(std::max(params[7], 0), 31)) << 24; + currScore |= static_cast(std::min(colorScore, 127)) << 17; + currScore |= static_cast(std::min(std::abs(params[4] - cfg.depth), 63)) << 11; + currScore |= static_cast(std::min(std::abs(1 - bNonLinearDepth), 1)) << 10; + currScore |= static_cast(std::min(std::abs(params[5] - cfg.stencil), 31)) << 6; + currScore |= static_cast(std::min(std::abs(params[3] - cfg.alpha), 31)) << 0; + /*------------------------------------------ANGLE's priority-----------------------------------------------*/ + + // if msaaEnabled, sampleBuffers and sampleCount should be greater than 0, until iterate to the last one(can't find). + bool const msaaLimit = (msaaEnabled ? (params[6] > 0 && params[7] > 0) : (params[6] == 0 && params[7] == 0)); + // performancePreferred ? [>=] : [<] , egl configurations store in "ascending order" + bool const filter = (currScore < lastScore) ^ qualityPreferred; + if ((filter && msaaLimit) || (!eglConfig && i == numConfig - 1)) { + eglConfig = eglConfigs[i]; + depth = params[4]; + stencil = params[5]; + sampleBuffers = params[6]; + sampleCount = params[7]; + lastScore = currScore; + } + } + return eglConfig; +} +} // namespace + +Context::~Context() { + resetCurrent(true); + + if (_context != EGL_NO_CONTEXT) { + eglDestroyContext(_display, _context); + } +} + +bool Context::createEGLContext(const ContextInfo &info) { + auto *instance = Instance::getInstance(); + + _config = chooseConfig(_display, info.config, info.qualityPreferred, info.msaaEnabled); + + _majorVersion = info.majorVersion; + _minorVersion = _majorVersion >= 3 ? 2 : 0; + ccstd::vector eglAttributes; + if (instance->checkExtension(CC_TOSTR(EGL_KHR_create_context))) { + eglAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); + eglAttributes.push_back(_majorVersion); + eglAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); + eglAttributes.push_back(_minorVersion); +#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION + eglAttributes.push_back(EGL_CONTEXT_FLAGS_KHR); + eglAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR); +#endif + eglAttributes.push_back(EGL_NONE); + + for (EGLint m = _minorVersion; m >= 0; --m) { + eglAttributes[3] = m; + _context = eglCreateContext(_display, _config, info.sharedContext, eglAttributes.data()); + auto err = eglGetError(); // QNX throws egl errors on mismatch + if (_context && err == EGL_SUCCESS) { + _minorVersion = m; + break; + } + } + } else { + eglAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + eglAttributes.push_back(_majorVersion); + eglAttributes.push_back(EGL_NONE); + EGL_CHECK(_context = eglCreateContext(_display, _config, info.sharedContext, eglAttributes.data())); + } + return _context != EGL_NO_CONTEXT; +} + +bool Context::createPBuffer() { + _pBuffer = std::make_unique(); + + EGLint pBufferAttribs[]{ + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE}; + return _pBuffer->init(_config, pBufferAttribs); +} + +bool Context::init(const ContextInfo &info) { + if (!createEGLContext(info)) { + return false; + } + + if (!createPBuffer()) { + return false; + } + + makeCurrent(); + return true; +} + +void Context::makeCurrent() { + makeCurrent(_pBuffer->getNativeHandle()); +} + +void Context::makeCurrent(EGLSurface surface) { + makeCurrent(surface, surface); +} + +void Context::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) { + if (_currentDrawSurface == drawSurface && _currentReadSurface == readSurface) { + return; + } + + EGL_CHECK(eglMakeCurrent(_display, drawSurface, readSurface, _context)); + _currentDrawSurface = drawSurface; + _currentReadSurface = readSurface; +} + +void Context::surfaceDestroy(EGLSurface surface) { + if (_currentReadSurface == surface || _currentDrawSurface == surface) { + resetCurrent(); + } +} + +void Context::resetCurrent(bool noContext) { + if (noContext) { + EGL_CHECK(eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); + _currentDrawSurface = EGL_NO_SURFACE; + _currentReadSurface = EGL_NO_SURFACE; + } else { + makeCurrent(); + } +} + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Context.h b/native/cocos/renderer/gfx-gles-common/egl/Context.h new file mode 100644 index 00000000000..1bf38de5096 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Context.h @@ -0,0 +1,58 @@ +#pragma once + +#include "base/std/container/vector.h" +#include "base/std/container/string.h" +#include "gfx-gles-common/egl/Surface.h" +#include "gfx-gles-common/egl/Base.h" +#include + +namespace cc::gfx::egl { + +struct ContextInfo { + Config config; + EGLContext sharedContext = EGL_NO_CONTEXT; + + EGLint majorVersion = 3; + bool msaaEnabled{false}; + bool qualityPreferred{false}; +}; + +class Context { +public: + Context() = default; + ~Context(); + + bool init(const ContextInfo &info); + + void makeCurrent(); + void makeCurrent(EGLSurface surface); + void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface); + void surfaceDestroy(EGLSurface surface); + void resetCurrent(bool noContext = false); + + EGLContext getContext() const { return _context; } + EGLConfig getConfig() const { return _config; } + EGLSurface getCurrentDrawSurface() const { return _currentDrawSurface; } + EGLSurface getCurrentReadSurface() const { return _currentReadSurface; } + + uint32_t getMinorVersion() const { return _glMinorVersion; } + uint32_t getMajorVersion() const { return _glMajorVersion; } +private: + bool createEGLContext(const ContextInfo &info); + bool createPBuffer(); + + EGLContext _context = EGL_NO_CONTEXT; + EGLDisplay _display = EGL_NO_DISPLAY; + EGLSurface _currentDrawSurface = EGL_NO_SURFACE; + EGLSurface _currentReadSurface = EGL_NO_SURFACE; + EGLConfig _config = EGL_NO_CONFIG_KHR; + + uint32_t _glMajorVersion{0U}; + uint32_t _glMinorVersion{0U}; + EGLint _majorVersion{0}; + EGLint _minorVersion{0}; + ccstd::vector _extensions; + std::unique_ptr _pBuffer; +}; + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp b/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp new file mode 100644 index 00000000000..87fc846996d --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp @@ -0,0 +1,166 @@ +#include "Instance.h" + +#include + +#include "base/Log.h" +#include "base/StringUtil.h" +#include "gfx-gles-common/egl/Base.h" +#include "gfx-gles-common/loader/eglw.h" +#include "gfx-gles-common/loader/gles2w.h" +#include "gfx-gles-common/loader/gles3w.h" + +namespace cc::gfx::egl { +namespace { +std::unique_ptr gLibEGL; +std::unique_ptr gLibGLES; +std::unique_ptr gInstance; +} + +void *getProcAddress(const char *proc) { + if (eglGetProcAddress) { + return reinterpret_cast(eglGetProcAddress(proc)); + } + return gLibEGL->getProcAddress(proc); +} + +namespace { +ccstd::string getFullDirectory() { + ccstd::string dir; +#if defined(_WIN32) + // In editor,there are same library,so we need to use abs path to load them. + HMODULE engine = nullptr; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(&getFullDirectory), &engine) != 0) { + + int times = 1; + do { + auto size = MAX_PATH * times++; + char *path = static_cast(CC_MALLOC(size)); + if (path) { + GetModuleFileNameA(engine, path, size); + dir = path; + } + CC_FREE(path); + } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER); + dir = dir.substr(0, dir.rfind('\\') + 1); + } else { + DWORD const err = GetLastError(); + CC_LOG_WARNING("Failed to get abs path for editor,error code:%lu", err); + } +#endif + return dir; +} + +bool loadLibrary() { + if (gLibEGL && gLibGLES) { + return true; + } + +#ifdef _WIN32 + ccstd::string libEGLPath = "libEGL.dll"; + ccstd::string libGLESV2Path; + ccstd::string libGLESV3Path = "libGLESv2.dll"; + #if CC_EDITOR + auto fullDir = getFullDirectory(); + libEGLPath = fullDir + libEGLPath; + libGLESV3Path = fullDir + libGLESV3Path; + #endif +#else + ccstd::string libEGLPath = "libEGL.so"; + ccstd::string libGLESV2Path = "libGLESv2.so"; + ccstd::string libGLESV3Path = "libGLESv3.so"; +#endif + + auto libEGL = std::make_unique(libEGLPath); + if (!libEGL->load()) { + return false; + } + + auto libGLES = std::make_unique(libGLESV3Path); + // usually gles2 && gles3 shares the same so, first load libGLESv3 + if (!libGLES->load() && !libGLESV2Path.empty()) { + // try libGLESv2 + libGLES = std::make_unique(libGLESV2Path); + if (!libGLES->load()) { + return false; + } + } + + eglwLoadProcs(getProcAddress); + gles2wLoadProcs(getProcAddress); + gles3wLoadProcs(getProcAddress); + + gLibEGL = std::move(libEGL); + gLibGLES = std::move(libGLES); + return true; +} +} // namespace +Instance *Instance::getInstance() { + return gInstance.get(); +} + +Instance::~Instance() { + terminateEGL(); +} + +bool Instance::initialize() { + if (!gInstance) { + gInstance.reset(ccnew Instance()); + if (!gInstance->initInternal()) { + gInstance = nullptr; + } + } + return static_cast(gInstance); +} + +void Instance::shutdown() { + gInstance = nullptr; +} + +bool Instance::initInternal() { +#ifndef __EMSCRIPTEN__ + if (!loadLibrary()) { + return false; + } +#endif + if (!initEGL()) { + return false; + } + + EGL_CHECK(_extensions = StringUtil::split(eglQueryString(_display, EGL_EXTENSIONS), " ")); + return true; +} + +bool Instance::initEGL() { + EGL_CHECK(_display = eglGetDisplay(EGL_DEFAULT_DISPLAY)); + + if (_display == EGL_NO_DISPLAY) { + CC_LOG_ERROR("eglGetDisplay() - FAILED."); + return false; + } + + EGLBoolean success; + EGL_CHECK(success = eglInitialize(_display, &_eglMajorVersion, &_eglMinorVersion)); + if (!success) { + CC_LOG_ERROR("eglInitialize() - FAILED."); + return false; + } + + EGL_CHECK(eglBindAPI(EGL_OPENGL_ES_API)); + return true; +} + +void Instance::terminateEGL() { + if (_display) { + EGL_CHECK(eglTerminate(_display)); + _display = EGL_NO_DISPLAY; + } +} + +bool Instance::checkExtension(const ccstd::string &extension) const { + return std::any_of(_extensions.begin(), _extensions.end(), [&extension](auto &ext) { + return ext.find(extension) != ccstd::string::npos; + }); +} +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Instance.h b/native/cocos/renderer/gfx-gles-common/egl/Instance.h new file mode 100644 index 00000000000..33691128314 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Instance.h @@ -0,0 +1,35 @@ +#pragma once + +#include "base/std/container/vector.h" +#include "base/std/container/string.h" +#include "base/DynamicLibrary.h" +#include "gfx-base/GFXDef-common.h" +#include "gfx-gles-common/egl/Base.h" +#include + +namespace cc::gfx::egl { + +class Instance { +public: + static Instance *getInstance(); + static bool initialize(); + static void shutdown(); + + ~Instance(); + + bool checkExtension(const ccstd::string &extension) const; +private: + Instance() = default; + bool initInternal(); + bool initEGL(); + void terminateEGL(); + + EGLDisplay _display{EGL_NO_DISPLAY}; + EGLint _eglMajorVersion{0}; + EGLint _eglMinorVersion{0}; + ccstd::vector _extensions; +}; + +void *getProcAddress(const char *proc); + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp b/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp new file mode 100644 index 00000000000..eb91990b070 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp @@ -0,0 +1,19 @@ +#include "Surface.h" + +namespace cc::gfx::egl { + +bool PBufferSurface::init(EGLConfig cfg, const EGLint *attributes) { + EGL_CHECK(_surface = eglCreatePbufferSurface(eglGetDisplay(EGL_DEFAULT_DISPLAY), cfg, attributes)); + return _surface != EGL_NO_SURFACE; +} + +bool WindowSurface::init(EGLConfig cfg, void *window) { + EGL_CHECK(_surface = eglCreateWindowSurface(_display, cfg, reinterpret_cast(window), nullptr)); + + eglQuerySurface(_display, _surface, EGL_WIDTH, &_width); + eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height); + + return _surface != EGL_NO_SURFACE; +} + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/egl/Surface.h b/native/cocos/renderer/gfx-gles-common/egl/Surface.h new file mode 100644 index 00000000000..fd05b99f443 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Surface.h @@ -0,0 +1,48 @@ +#include "gfx-gles-common/egl/Base.h" +#include "gfx-base/GFXDeviceObject.h" + +namespace cc::gfx::egl { + +class Surface : public GFXDeviceObject { +public: + Surface() { + _display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + } + + ~Surface() override { + if (_surface != EGL_NO_CONFIG_KHR) { + eglDestroySurface(_display, _surface); + } + } + + EGLSurface getNativeHandle() const { return _surface; }; + void swapBuffer() { eglSwapBuffers(_display, _surface); }; + +protected: + EGLDisplay _display = EGL_NO_DISPLAY; + EGLSurface _surface = EGL_NO_SURFACE; +}; + +class WindowSurface : public Surface { +public: + WindowSurface() = default; + ~WindowSurface() override = default; + + bool init(EGLConfig cfg, void *window); + EGLint getWidth() const { return _width; } + EGLint getHeight() const { return _height; } + +private: + EGLint _width = 1; + EGLint _height = 1; +}; + +class PBufferSurface : public Surface { +public: + PBufferSurface() = default; + ~PBufferSurface() override = default; + + bool init(EGLConfig cfg, const EGLint *attributes); +}; + +} // namespace cc::gfx::egl diff --git a/native/cocos/renderer/gfx-gles-common/eglw.cpp b/native/cocos/renderer/gfx-gles-common/loader/eglw.cpp similarity index 100% rename from native/cocos/renderer/gfx-gles-common/eglw.cpp rename to native/cocos/renderer/gfx-gles-common/loader/eglw.cpp diff --git a/native/cocos/renderer/gfx-gles-common/eglw.h b/native/cocos/renderer/gfx-gles-common/loader/eglw.h similarity index 100% rename from native/cocos/renderer/gfx-gles-common/eglw.h rename to native/cocos/renderer/gfx-gles-common/loader/eglw.h diff --git a/native/cocos/renderer/gfx-gles-common/gles2w.cpp b/native/cocos/renderer/gfx-gles-common/loader/gles2w.cpp similarity index 100% rename from native/cocos/renderer/gfx-gles-common/gles2w.cpp rename to native/cocos/renderer/gfx-gles-common/loader/gles2w.cpp diff --git a/native/cocos/renderer/gfx-gles-common/gles2w.h b/native/cocos/renderer/gfx-gles-common/loader/gles2w.h similarity index 100% rename from native/cocos/renderer/gfx-gles-common/gles2w.h rename to native/cocos/renderer/gfx-gles-common/loader/gles2w.h diff --git a/native/cocos/renderer/gfx-gles-common/gles3w.cpp b/native/cocos/renderer/gfx-gles-common/loader/gles3w.cpp similarity index 100% rename from native/cocos/renderer/gfx-gles-common/gles3w.cpp rename to native/cocos/renderer/gfx-gles-common/loader/gles3w.cpp diff --git a/native/cocos/renderer/gfx-gles-common/gles3w.h b/native/cocos/renderer/gfx-gles-common/loader/gles3w.h similarity index 100% rename from native/cocos/renderer/gfx-gles-common/gles3w.h rename to native/cocos/renderer/gfx-gles-common/loader/gles3w.h diff --git a/native/cocos/renderer/gfx-gles2/GLES2Wrangler.h b/native/cocos/renderer/gfx-gles2/GLES2Wrangler.h index 239848bbc16..50b2dece2c6 100644 --- a/native/cocos/renderer/gfx-gles2/GLES2Wrangler.h +++ b/native/cocos/renderer/gfx-gles2/GLES2Wrangler.h @@ -24,8 +24,8 @@ #pragma once -#include "../gfx-gles-common/eglw.h" -#include "../gfx-gles-common/gles2w.h" +#include "../gfx-gles-common/loader/eglw.h" +#include "../gfx-gles-common/loader/gles2w.h" bool gles2wInit(); bool gles2wExit(); diff --git a/native/cocos/renderer/gfx-gles3/GLES3Wrangler.h b/native/cocos/renderer/gfx-gles3/GLES3Wrangler.h index 7aad4852232..cc2c5ca8a40 100644 --- a/native/cocos/renderer/gfx-gles3/GLES3Wrangler.h +++ b/native/cocos/renderer/gfx-gles3/GLES3Wrangler.h @@ -24,9 +24,9 @@ #pragma once -#include "../gfx-gles-common/eglw.h" -#include "../gfx-gles-common/gles2w.h" -#include "../gfx-gles-common/gles3w.h" +#include "../gfx-gles-common/loader/eglw.h" +#include "../gfx-gles-common/loader/gles2w.h" +#include "../gfx-gles-common/loader/gles3w.h" PFNGLES3WLOADPROC pfnGLES3wLoadProc(); bool gles3wInit(); From 342312d694b5089bae51dc79301a39b9dbf6067f Mon Sep 17 00:00:00 2001 From: zach Date: Fri, 28 Jul 2023 14:05:23 +0800 Subject: [PATCH 2/2] [refactoring]gfx gles common objects. --- editor/assets/primitives.fbx.meta | 2 +- native/CMakeLists.txt | 101 +- native/cocos/renderer/GFXDeviceManager.cpp | 103 ++ native/cocos/renderer/GFXDeviceManager.h | 84 +- .../cocos/renderer/gfx-base/GFXDef-common.h | 1 - .../gfx-gles-common/common/GLESBase.h | 52 + .../gfx-gles-common/common/GLESBuffer.cpp | 68 + .../gfx-gles-common/common/GLESBuffer.h | 26 + .../common/GLESCommandBuffer.cpp | 208 +++ .../common/GLESCommandBuffer.h | 80 ++ .../common/GLESCommandEncoder.h | 55 + .../common/GLESCommandStorage.cpp | 21 +- .../common/GLESCommandStorage.h | 9 +- .../gfx-gles-common/common/GLESCommands.cpp | 171 +++ .../gfx-gles-common/common/GLESCommands.h | 106 ++ .../common/GLESDescriptorSet.cpp | 74 ++ .../common/GLESDescriptorSet.h | 25 + .../common/GLESDescriptorSetLayout.cpp | 40 + .../common/GLESDescriptorSetLayout.h | 22 + .../gfx-gles-common/common/GLESDevice.cpp | 283 +++++ .../gfx-gles-common/common/GLESDevice.h | 147 +++ .../common/GLESFramebuffer.cpp | 58 + .../gfx-gles-common/common/GLESFramebuffer.h | 23 + .../gfx-gles-common/common/GLESGPUObjects.h | 303 +++++ .../common/GLESGeneralBarrier.cpp | 21 + .../common/GLESGeneralBarrier.h | 20 + .../common/GLESInputAssembler.cpp | 38 + .../common/GLESInputAssembler.h | 22 + .../common/GLESPipelineCache.cpp | 191 +++ .../common/GLESPipelineCache.h | 42 + .../common/GLESPipelineLayout.cpp | 29 + .../common/GLESPipelineLayout.h | 22 + .../common/GLESPipelineState.cpp | 101 ++ .../common/GLESPipelineState.h | 23 + .../gfx-gles-common/common/GLESQueue.cpp | 66 +- .../gfx-gles-common/common/GLESQueue.h | 38 +- .../gfx-gles-common/common/GLESRecycleBin.cpp | 53 + .../gfx-gles-common/common/GLESRecycleBin.h | 25 + .../gfx-gles-common/common/GLESRenderPass.cpp | 56 + .../gfx-gles-common/common/GLESRenderPass.h | 21 + .../gfx-gles-common/common/GLESSampler.cpp | 24 + .../gfx-gles-common/common/GLESSampler.h | 18 + .../gfx-gles-common/common/GLESShader.cpp | 40 + .../gfx-gles-common/common/GLESShader.h | 22 + .../gfx-gles-common/common/GLESSwapchain.cpp | 189 +++ .../gfx-gles-common/common/GLESSwapchain.h | 30 + .../gfx-gles-common/common/GLESTexture.cpp | 150 +++ .../gfx-gles-common/common/GLESTexture.h | 29 + .../cocos/renderer/gfx-gles-common/egl/Base.h | 18 - .../renderer/gfx-gles-common/egl/Context.cpp | 21 +- .../renderer/gfx-gles-common/egl/Context.h | 24 +- .../renderer/gfx-gles-common/egl/Debug.h | 31 + .../renderer/gfx-gles-common/egl/Instance.cpp | 18 +- .../renderer/gfx-gles-common/egl/Surface.cpp | 10 +- .../renderer/gfx-gles-common/egl/Surface.h | 6 +- .../gles2/GLES2CommandEncoder.cpp | 6 + .../gles2/GLES2CommandEncoder.h | 12 + .../gfx-gles-common/gles2/GLES2Commands.cpp | 33 + .../gfx-gles-common/gles2/GLES2Commands.h | 53 + .../gfx-gles-common/gles2/GLES2Features.cpp | 280 ++++ .../gfx-gles-common/gles2/GLES2Types.inl | 330 +++++ .../gles3/GLES3CommandEncoder.cpp | 756 +++++++++++ .../gles3/GLES3CommandEncoder.h | 58 + .../gfx-gles-common/gles3/GLES3Commands.cpp | 1122 +++++++++++++++++ .../gfx-gles-common/gles3/GLES3Commands.h | 85 ++ .../gfx-gles-common/gles3/GLES3Features.cpp | 316 +++++ .../gfx-gles-common/gles3/GLES3Types.inl | 518 ++++++++ 67 files changed, 6859 insertions(+), 170 deletions(-) create mode 100644 native/cocos/renderer/GFXDeviceManager.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESBase.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESBuffer.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESBuffer.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommandEncoder.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommands.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESCommands.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDevice.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESDevice.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESGPUObjects.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESSampler.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESSampler.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESShader.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESShader.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.h create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESTexture.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/common/GLESTexture.h create mode 100644 native/cocos/renderer/gfx-gles-common/egl/Debug.h create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.h create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.h create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2Features.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles2/GLES2Types.inl create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.h create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.h create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3Features.cpp create mode 100644 native/cocos/renderer/gfx-gles-common/gles3/GLES3Types.inl diff --git a/editor/assets/primitives.fbx.meta b/editor/assets/primitives.fbx.meta index 5221ff981fc..d749817046b 100644 --- a/editor/assets/primitives.fbx.meta +++ b/editor/assets/primitives.fbx.meta @@ -171,7 +171,7 @@ "displayName": "", "id": "aae0f", "name": "primitives.prefab", - "ver": "1.0.13", + "ver": "1.0.14", "imported": true, "files": [ ".json" diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 7512550daa2..8b7ae41a7c1 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -62,6 +62,7 @@ elseif(ANDROID OR WINDOWS OR OHOS) cc_set_if_undefined(CC_USE_GLES3 ON) cc_set_if_undefined(CC_USE_VULKAN OFF) cc_set_if_undefined(CC_USE_GLES2 OFF) + cc_set_if_undefined(CC_USE_GLES_NEW OFF) elseif(MACOSX OR IOS) cc_set_if_undefined(CC_USE_METAL ON) cc_set_if_undefined(CC_USE_VULKAN OFF) @@ -1171,6 +1172,7 @@ cocos_source_files( cocos/renderer/core/TextureBufferPool.h cocos/renderer/core/TextureBufferPool.cpp + cocos/renderer/GFXDeviceManager.cpp cocos/renderer/GFXDeviceManager.h cocos/renderer/gfx-base/SPIRVUtils.h @@ -1614,18 +1616,61 @@ cocos_source_files( # ) if(CC_USE_GLES2 OR CC_USE_GLES3) - cocos_source_files( - cocos/renderer/gfx-gles-common/common/GLESQueue.cpp - cocos/renderer/gfx-gles-common/common/GLESQueue.h - cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp - cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h - cocos/renderer/gfx-gles-common/egl/Context.cpp - cocos/renderer/gfx-gles-common/egl/Context.h - cocos/renderer/gfx-gles-common/egl/Surface.cpp - cocos/renderer/gfx-gles-common/egl/Surface.h - cocos/renderer/gfx-gles-common/egl/Instance.cpp - cocos/renderer/gfx-gles-common/egl/Instance.h - ) + if(CC_USE_GLES_NEW) + cocos_source_files( + cocos/renderer/gfx-gles-common/egl/Context.cpp + cocos/renderer/gfx-gles-common/egl/Context.h + cocos/renderer/gfx-gles-common/egl/Surface.cpp + cocos/renderer/gfx-gles-common/egl/Surface.h + cocos/renderer/gfx-gles-common/egl/Instance.cpp + cocos/renderer/gfx-gles-common/egl/Instance.h + ) + + cocos_source_files( + cocos/renderer/gfx-gles-common/common/GLESQueue.cpp + cocos/renderer/gfx-gles-common/common/GLESQueue.h + cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp + cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h + + cocos/renderer/gfx-gles-common/common/GLESCommands.cpp + cocos/renderer/gfx-gles-common/common/GLESCommands.h + cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.cpp + cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.h + cocos/renderer/gfx-gles-common/common/GLESBuffer.cpp + cocos/renderer/gfx-gles-common/common/GLESBuffer.h + cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.cpp + cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.h + cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.cpp + cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.h + cocos/renderer/gfx-gles-common/common/GLESDevice.cpp + cocos/renderer/gfx-gles-common/common/GLESDevice.h + cocos/renderer/gfx-gles-common/common/GLESFramebuffer.cpp + cocos/renderer/gfx-gles-common/common/GLESFramebuffer.h + cocos/renderer/gfx-gles-common/common/GLESInputAssembler.cpp + cocos/renderer/gfx-gles-common/common/GLESInputAssembler.h + cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.cpp + cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.h + cocos/renderer/gfx-gles-common/common/GLESPipelineState.cpp + cocos/renderer/gfx-gles-common/common/GLESPipelineState.h + cocos/renderer/gfx-gles-common/common/GLESRenderPass.cpp + cocos/renderer/gfx-gles-common/common/GLESRenderPass.h + cocos/renderer/gfx-gles-common/common/GLESSampler.cpp + cocos/renderer/gfx-gles-common/common/GLESSampler.h + cocos/renderer/gfx-gles-common/common/GLESShader.cpp + cocos/renderer/gfx-gles-common/common/GLESShader.h + cocos/renderer/gfx-gles-common/common/GLESSwapchain.cpp + cocos/renderer/gfx-gles-common/common/GLESSwapchain.h + cocos/renderer/gfx-gles-common/common/GLESTexture.cpp + cocos/renderer/gfx-gles-common/common/GLESTexture.h + cocos/renderer/gfx-gles-common/common/GLESGPUObjects.h + cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.cpp + cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.h + cocos/renderer/gfx-gles-common/common/GLESPipelineCache.cpp + cocos/renderer/gfx-gles-common/common/GLESPipelineCache.h + cocos/renderer/gfx-gles-common/common/GLESRecycleBin.cpp + cocos/renderer/gfx-gles-common/common/GLESRecycleBin.h + ) + endif() cocos_source_files( cocos/renderer/gfx-gles-common/GLESCommandPool.h @@ -1640,7 +1685,8 @@ if(CC_USE_GLES2 OR CC_USE_GLES3) endif() if(CC_USE_GLES2) - cocos_source_files( +# if(!CC_USE_GLES_NEW) + cocos_source_files( cocos/renderer/gfx-gles2/GLES2Buffer.cpp cocos/renderer/gfx-gles2/GLES2Buffer.h cocos/renderer/gfx-gles2/GLES2CommandBuffer.cpp @@ -1682,11 +1728,21 @@ if(CC_USE_GLES2) cocos/renderer/gfx-gles2/GLES2Wrangler.h cocos/renderer/gfx-gles2/states/GLES2Sampler.cpp cocos/renderer/gfx-gles2/states/GLES2Sampler.h - ) + ) +# else() + cocos_source_files( + cocos/renderer/gfx-gles-common/gles2/GLES2Commands.cpp + cocos/renderer/gfx-gles-common/gles2/GLES2Commands.h + cocos/renderer/gfx-gles-common/gles2/GLES2Features.cpp + cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.cpp + cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.h + ) +# endif() endif() if(CC_USE_GLES3) - cocos_source_files( +# if(!CC_USE_GLES_NEW) + cocos_source_files( cocos/renderer/gfx-gles3/GLES3Buffer.cpp cocos/renderer/gfx-gles3/GLES3Buffer.h cocos/renderer/gfx-gles3/GLES3CommandBuffer.cpp @@ -1732,7 +1788,16 @@ if(CC_USE_GLES3) cocos/renderer/gfx-gles3/states/GLES3GeneralBarrier.h cocos/renderer/gfx-gles3/states/GLES3Sampler.cpp cocos/renderer/gfx-gles3/states/GLES3Sampler.h - ) + ) +# else() + cocos_source_files( + cocos/renderer/gfx-gles-common/gles3/GLES3Commands.cpp + cocos/renderer/gfx-gles-common/gles3/GLES3Commands.h + cocos/renderer/gfx-gles-common/gles3/GLES3Features.cpp + cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.cpp + cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.h + ) +# endif() endif() if(CC_USE_METAL) @@ -3151,6 +3216,10 @@ if(CC_USE_GLES2) target_compile_definitions(${ENGINE_NAME} PUBLIC CC_USE_GLES2) endif() +if(CC_USE_GLES_NEW) + target_compile_definitions(${ENGINE_NAME} PUBLIC CC_USE_GLES_NEW) +endif() + target_include_directories(${ENGINE_NAME} PUBLIC ${CC_EXTERNAL_INCLUDES} diff --git a/native/cocos/renderer/GFXDeviceManager.cpp b/native/cocos/renderer/GFXDeviceManager.cpp new file mode 100644 index 00000000000..608a5ab33b0 --- /dev/null +++ b/native/cocos/renderer/GFXDeviceManager.cpp @@ -0,0 +1,103 @@ +#include "GFXDeviceManager.h" + + +#ifdef CC_USE_NVN + #include "gfx-nvn/NVNDevice.h" +#endif + +#ifdef CC_USE_VULKAN + #include "gfx-vulkan/VKDevice.h" +#endif + +#ifdef CC_USE_METAL + #include "gfx-metal/MTLDevice.h" +#endif + +#ifdef CC_USE_GLES3 + #include "gfx-gles3/GLES3Device.h" +#endif + +#ifdef CC_USE_GLES2 + #include "gfx-gles2/GLES2Device.h" +#endif + +#ifdef CC_USE_GLES_NEW + #include "gfx-gles-common/common/GLESDevice.h" +#endif + +#include "gfx-empty/EmptyDevice.h" + +namespace cc::gfx { +namespace { +#ifdef CC_USE_GLES_NEW +constexpr bool DETACH_DEVICE_THREAD{false}; +constexpr bool FORCE_DISABLE_VALIDATION{true}; +constexpr bool FORCE_ENABLE_VALIDATION{false}; +#else +constexpr bool DETACH_DEVICE_THREAD{true}; +constexpr bool FORCE_DISABLE_VALIDATION{false}; +constexpr bool FORCE_ENABLE_VALIDATION{false}; +#endif +} // namespace + +bool DeviceManager::isDetachDeviceThread() { + return DETACH_DEVICE_THREAD && Device::isSupportDetachDeviceThread; +} + +bool DeviceManager::isValidationSupported() { + return !FORCE_DISABLE_VALIDATION || FORCE_ENABLE_VALIDATION; +} + +Device *DeviceManager::create(const DeviceInfo &info) { + if (Device::instance) return Device::instance; + + Device *device = nullptr; + +#ifdef CC_USE_NVN + if (tryCreate(info, &device)) return device; +#endif + +#ifdef CC_USE_VULKAN + #if XR_OEM_PICO + Device::isSupportDetachDeviceThread = false; + #endif + + bool skipVulkan = false; + #if CC_PLATFORM == CC_PLATFORM_ANDROID + auto sdkVersion = BasePlatform::getPlatform()->getSdkVersion(); + skipVulkan = sdkVersion <= 27; // Android 8 + #endif +// if (!skipVulkan && tryCreate(info, &device)) return device; +#endif + +#ifdef CC_USE_METAL + if (tryCreate(info, &device)) return device; +#endif + +#ifdef CC_USE_GLES_NEW + if (tryCreate(info, &device)) return device; +#endif + +#ifdef CC_USE_GLES3 + #if CC_USE_XR || CC_USE_AR_MODULE + Device::isSupportDetachDeviceThread = false; + #endif + if (tryCreate(info, &device)) return device; +#endif + +#ifdef CC_USE_GLES2 + // arcore & arengine currently only supports gles, session update requires gl context + #if CC_USE_AR_MODULE + Device::isSupportDetachDeviceThread = false; + #endif + if (tryCreate(info, &device)) return device; +#endif + +#ifdef CC_EDITOR + Device::isSupportDetachDeviceThread = false; +#endif + if (tryCreate(info, &device)) return device; + + return nullptr; +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/GFXDeviceManager.h b/native/cocos/renderer/GFXDeviceManager.h index 04fda885a05..bd3f1c5aa9f 100644 --- a/native/cocos/renderer/GFXDeviceManager.h +++ b/native/cocos/renderer/GFXDeviceManager.h @@ -35,95 +35,19 @@ // #undef CC_USE_METAL // #undef CC_USE_GLES3 // #undef CC_USE_GLES2 - -#ifdef CC_USE_NVN - #include "gfx-nvn/NVNDevice.h" -#endif - -#ifdef CC_USE_VULKAN - #include "gfx-vulkan/VKDevice.h" -#endif - -#ifdef CC_USE_METAL - #include "gfx-metal/MTLDevice.h" -#endif - -#ifdef CC_USE_GLES3 - #include "gfx-gles3/GLES3Device.h" -#endif - -#ifdef CC_USE_GLES2 - #include "gfx-gles2/GLES2Device.h" -#endif - -#include "gfx-empty/EmptyDevice.h" #include "renderer/pipeline/Define.h" namespace cc { namespace gfx { class CC_DLL DeviceManager final { - static constexpr bool DETACH_DEVICE_THREAD{true}; - static constexpr bool FORCE_DISABLE_VALIDATION{false}; - static constexpr bool FORCE_ENABLE_VALIDATION{false}; - public: static Device *create() { DeviceInfo deviceInfo{pipeline::bindingMappingInfo}; return DeviceManager::create(deviceInfo); } - - static Device *create(const DeviceInfo &info) { - if (Device::instance) return Device::instance; - - Device *device = nullptr; - -#ifdef CC_USE_NVN - if (tryCreate(info, &device)) return device; -#endif - -#ifdef CC_USE_VULKAN - #if XR_OEM_PICO - Device::isSupportDetachDeviceThread = false; - #endif - - bool skipVulkan = false; -#if CC_PLATFORM == CC_PLATFORM_ANDROID - auto sdkVersion = BasePlatform::getPlatform()->getSdkVersion(); - skipVulkan = sdkVersion <= 27; // Android 8 -#endif - if (!skipVulkan && tryCreate(info, &device)) return device; -#endif - -#ifdef CC_USE_METAL - if (tryCreate(info, &device)) return device; -#endif - -#ifdef CC_USE_GLES3 - #if CC_USE_XR || CC_USE_AR_MODULE - Device::isSupportDetachDeviceThread = false; - #endif - if (tryCreate(info, &device)) return device; -#endif - -#ifdef CC_USE_GLES2 - // arcore & arengine currently only supports gles, session update requires gl context - #if CC_USE_AR_MODULE - Device::isSupportDetachDeviceThread = false; - #endif - if (tryCreate(info, &device)) return device; -#endif - -#ifdef CC_EDITOR - Device::isSupportDetachDeviceThread = false; -#endif - if (tryCreate(info, &device)) return device; - - return nullptr; - } - - static bool isDetachDeviceThread() { - return DETACH_DEVICE_THREAD && Device::isSupportDetachDeviceThread; - } + static bool isDetachDeviceThread(); + static bool isValidationSupported(); + static Device *create(const DeviceInfo &info); static ccstd::string getGFXName() { ccstd::string gfx = "unknown"; @@ -154,7 +78,7 @@ class CC_DLL DeviceManager final { } #if !defined(CC_SERVER_MODE) - if (CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION || FORCE_ENABLE_VALIDATION) { + if (CC_DEBUG > 0 && isValidationSupported()) { device = ccnew gfx::DeviceValidator(device); } #endif diff --git a/native/cocos/renderer/gfx-base/GFXDef-common.h b/native/cocos/renderer/gfx-base/GFXDef-common.h index ab5c7bd810f..c3ccca605c9 100644 --- a/native/cocos/renderer/gfx-base/GFXDef-common.h +++ b/native/cocos/renderer/gfx-base/GFXDef-common.h @@ -85,7 +85,6 @@ class CommandBuffer; class Queue; class QueryPool; class Window; -class Context; using BufferBarrierList = ccstd::vector; using TextureBarrierList = ccstd::vector; diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESBase.h b/native/cocos/renderer/gfx-gles-common/common/GLESBase.h new file mode 100644 index 00000000000..4af7cbf96b1 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESBase.h @@ -0,0 +1,52 @@ +#pragma once + +#include "base/std/container/array.h" +#include "gfx-base/GFXDef-common.h" +#include "gfx-gles-common/loader/gles2w.h" +// remote in future +#include "gfx-gles-common/GLESCommandPool.h" + +namespace cc::gfx { +static constexpr uint32_t QUEUE_NUM = static_cast(QueueType::TRANSFER) + 1; +static constexpr uint32_t MAX_CONTEXT_NUM = QUEUE_NUM; + +struct GLESGPUStateCache { + RasterizerState rs; + DepthStencilState dss; + BlendState bs; + GLenum primitive = GL_TRIANGLES; + + GLuint glProgram = 0; + + GLuint drawFrameBuffer = 0; + GLuint readFrameBuffer = 0; + + bool isCullFaceEnabled = true; + bool isStencilTestEnabled = false; + + Viewport viewport; + Rect scissor; + + ccstd::array glEnabledAttribLocs; + ccstd::array glCurrentAttribLocs; +}; + +struct GLESGPUConstantRegistry { + MSRTSupportLevel mMSRT{MSRTSupportLevel::NONE}; + FBFSupportLevel mFBF{FBFSupportLevel::NONE}; + + GLuint majorVersion{3}; + GLuint minorVersion{2}; + + // for gles2 + bool useVAO = false; + bool useDrawInstanced = false; + bool useInstancedArrays = false; + bool useDiscardFramebuffer = false; + + ccstd::string fbfLevelStr; + ccstd::string msaaLevelStr; + ccstd::string compressedFmts; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.cpp new file mode 100644 index 00000000000..a6cda7c882d --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.cpp @@ -0,0 +1,68 @@ +#include "GLESBuffer.h" +#include "GLESCommands.h" +#include "GLESDevice.h" + +namespace cc::gfx { + +GLESBuffer::GLESBuffer() { + _typedID = generateObjectID(); +} + +GLESBuffer::~GLESBuffer() { + destroy(); +} + +void GLESBuffer::doInit(const BufferInfo & /*info*/) { + _gpuBufferView = ccnew GLESGPUBufferView; + _gpuBufferView->offset = 0; + _gpuBufferView->range = _size; + + _gpuBufferView->gpuBuffer = ccnew GLESGPUBuffer; + _gpuBufferView->gpuBuffer->usage = _usage; + _gpuBufferView->gpuBuffer->memUsage = _memUsage; + _gpuBufferView->gpuBuffer->size = _size; + _gpuBufferView->stride = _stride; + + glesCreateBuffer(GLESDevice::getInstance(), _gpuBufferView->gpuBuffer); +} + +void GLESBuffer::doInit(const BufferViewInfo &info) { + auto *buffer = static_cast(info.buffer); + _gpuBufferView = ccnew GLESGPUBufferView; + _gpuBufferView->gpuBuffer = buffer->_gpuBufferView->gpuBuffer; + _gpuBufferView->offset = info.offset; + _gpuBufferView->range = info.range; + _gpuBufferView->stride = _stride; +} + +void GLESBuffer::doDestroy() { + _gpuBufferView = nullptr; +} + +void GLESBuffer::doResize(uint32_t size, uint32_t /*count*/) { + _gpuBufferView->gpuBuffer->size = size; + _gpuBufferView->range = size; + glesResizeBuffer(GLESDevice::getInstance(), _gpuBufferView->gpuBuffer); +} + +void GLESBuffer::update(const void *buffer, uint32_t size) { + auto *gpuBuffer = _gpuBufferView->gpuBuffer.get(); + + auto *queue = GLESDevice::getInstance()->getQueue(QueueType::GRAPHICS); + if (queue->isAsyncQueue()) { + uint8_t *tmp = GLESDevice::getInstance()->stagingBuffer()->allocate(size); + memcpy(tmp, buffer, size); + GLESDevice::getInstance()->getQueue(QueueType::GRAPHICS)->queueTask( + [=]() { + glesUpdateBuffer(GLESDevice::getInstance(), gpuBuffer, tmp, 0, size, true, true); + }); + } else { + glesUpdateBuffer(GLESDevice::getInstance(), gpuBuffer, buffer, 0, size, true, true); + } +} + +GLESGPUBuffer::~GLESGPUBuffer() { + GLESDevice::getInstance()->recycleBin()->collect(this); +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.h b/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.h new file mode 100644 index 00000000000..fae378bfd92 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESBuffer.h @@ -0,0 +1,26 @@ +#pragma once + +#include "gfx-base/GFXBuffer.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESBuffer final : public Buffer { +public: + GLESBuffer(); + ~GLESBuffer() override; + + GLESGPUBuffer *gpuBuffer() const { return _gpuBufferView->gpuBuffer; } + GLESGPUBufferView *gpuBufferView() const { return _gpuBufferView; } + + void update(const void *buffer, uint32_t size) override; +protected: + void doInit(const BufferInfo &info) override; + void doInit(const BufferViewInfo &info) override; + void doDestroy() override; + void doResize(uint32_t size, uint32_t count) override; + + IntrusivePtr _gpuBufferView; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.cpp new file mode 100644 index 00000000000..4735bc2536f --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.cpp @@ -0,0 +1,208 @@ +#include "GLESCommandBuffer.h" +#include "GLESRenderPass.h" +#include "GLESFramebuffer.h" +#include "GLESQueue.h" +#include "GLESPipelineState.h" +#include "GLESDescriptorSet.h" +#include "GLESInputAssembler.h" +#include "GLESTexture.h" +#include "GLESBuffer.h" +#include "GLESCommands.h" +#include "GLESDevice.h" + +namespace cc::gfx { +constexpr uint64_t FENCE_WAIT_TIMEOUT = 1 * 1000 * 1000 * 1000; + +GLESCommandBuffer::GLESCommandBuffer() { + _typedID = generateObjectID(); + _storage = std::make_unique(); + _encoder.reset(createGLESCommandEncoder(GLESDevice::getInstance()->constantRegistry().majorVersion)); + + auto *device = GLESDevice::getInstance(); + // default attach to main context. + auto *mainContext = device->getMainContext(); + _encoder->attachContext(mainContext, device->getCacheState(mainContext->getContextID())); + + _fence = std::make_unique(); +} + +GLESCommandBuffer::~GLESCommandBuffer() { + destroy(); +} + +void GLESCommandBuffer::begin(RenderPass * /*renderPass*/, uint32_t /*subPass*/, Framebuffer * /*frameBuffer*/) { + _glesQueue->wait(_lastTaskHandle); + _storage->reset(); + enqueueCmd(&GLESCommandEncoder::begin, _encoder.get(), _fence.get()); +} + +void GLESCommandBuffer::end() { + enqueueCmd(&GLESCommandEncoder::end, _encoder.get(), _fence.get()); +} + +void GLESCommandBuffer::beginRenderPass(RenderPass *renderPass, + Framebuffer *fbo, + const Rect &renderArea, + const Color *colors, + float depth, + uint32_t stencil, + CommandBuffer *const * /*secondaryCBs*/, + uint32_t /*secondaryCBCount*/) { + auto *pass = static_cast(renderPass); + enqueueCmd(&GLESCommandEncoder::beginRenderPass, _encoder.get(), + PassBeginInfo { + static_cast(fbo)->gpuFramebuffer(), + reinterpret_cast(copyOrAssignData(colors, pass->getColorAttachments().size())), + depth, + stencil, + renderArea + }); +} + +void GLESCommandBuffer::endRenderPass() { + enqueueCmd(&GLESCommandEncoder::endRenderPass, _encoder.get()); +} + +void GLESCommandBuffer::nextSubpass() { + enqueueCmd(&GLESCommandEncoder::nextSubPass, _encoder.get()); +} + +void GLESCommandBuffer::bindPipelineState(PipelineState *pso) { + enqueueCmd(&GLESCommandEncoder::bindPipelineState, _encoder.get(), static_cast(pso)->gpuPipelineState()); +} + +void GLESCommandBuffer::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) { + enqueueCmd(&GLESCommandEncoder::bindDescriptorSet, _encoder.get(), set, + DescriptorBindInfo{ + static_cast(descriptorSet)->gpuDescriptorSet(), + copyOrAssignData(dynamicOffsets, dynamicOffsetCount), + dynamicOffsetCount, + }); +} + +void GLESCommandBuffer::bindInputAssembler(InputAssembler *ia) { + enqueueCmd(&GLESCommandEncoder::bindInputAssembler, _encoder.get(), static_cast(ia)->gpuInputAssembler()); +} + +void GLESCommandBuffer::setViewport(const Viewport &vp) { + enqueueCmd(&GLESCommandEncoder::setViewport, _encoder.get(), vp); +} + +void GLESCommandBuffer::setScissor(const Rect &rect) { + enqueueCmd(&GLESCommandEncoder::setScissor, _encoder.get(), rect); +} + +void GLESCommandBuffer::setLineWidth(float width) { + enqueueCmd(&GLESCommandEncoder::setLineWidth, _encoder.get(), width); +} + +void GLESCommandBuffer::setDepthBias(float constant, float clamp, float slope) { + enqueueCmd(&GLESCommandEncoder::setDepthBias, _encoder.get(), constant, clamp, slope); +} + +void GLESCommandBuffer::setBlendConstants(const Color &constants) { + enqueueCmd(&GLESCommandEncoder::setBlendConstants, _encoder.get(), constants); +} + +void GLESCommandBuffer::setDepthBound(float minBounds, float maxBounds) { + enqueueCmd(&GLESCommandEncoder::setDepthBound, _encoder.get(), minBounds, maxBounds); +} + +void GLESCommandBuffer::setStencilWriteMask(StencilFace face, uint32_t mask) { + enqueueCmd(&GLESCommandEncoder::setStencilWriteMask, _encoder.get(), face, mask); +} + +void GLESCommandBuffer::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) { + enqueueCmd(&GLESCommandEncoder::setStencilCompareMask, _encoder.get(), face, ref, mask); +} + +void GLESCommandBuffer::draw(const DrawInfo &info) { + enqueueCmd(&GLESCommandEncoder::draw, _encoder.get(), info); +} + +void GLESCommandBuffer::updateBuffer(Buffer *buff, const void *data, uint32_t size) { + enqueueCmd(&GLESCommandEncoder::updateBuffer, _encoder.get(), static_cast(buff)->gpuBuffer(), + copyOrAssignDataImpl(data, size), size); +} + +void GLESCommandBuffer::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) { +// glesCopyBuffersToTexture(GLESDevice::getInstance(), buffers, static_cast(texture)->gpuTexture(), regions, count); +} + +void GLESCommandBuffer::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) { + +} + +void GLESCommandBuffer::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) { + +} + +void GLESCommandBuffer::resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) { + +} + +void GLESCommandBuffer::execute(CommandBuffer *const *cmdBuffs, uint32_t count) { + // do nothing +} + +void GLESCommandBuffer::dispatch(const DispatchInfo &info) { + if (info.indirectBuffer == nullptr) { + enqueueCmd(&GLESCommandEncoder::dispatch, _encoder.get(), info.groupCountX, info.groupCountY, info.groupCountZ); + } +} + +void GLESCommandBuffer::pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const * /*buffers*/, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const * /*textures*/, uint32_t textureBarrierCount) { + +} + +void GLESCommandBuffer::beginQuery(QueryPool *queryPool, uint32_t id) { + +} + +void GLESCommandBuffer::endQuery(QueryPool *queryPool, uint32_t id) { + +} + +void GLESCommandBuffer::resetQueryPool(QueryPool *queryPool) { + +} + +void GLESCommandBuffer::attachContext(egl::Context *context) { + _encoder->attachContext(context, GLESDevice::getInstance()->getCacheState(context->getContextID())); +} + +void GLESCommandBuffer::setTaskHandle(GLESQueue::TaskHandle handle) { + _lastTaskHandle = handle; +} + +void GLESCommandBuffer::executeCommands() { + _storage->execute(); +} + +void GLESCommandBuffer::doInit(const CommandBufferInfo & /*info*/) { + _glesQueue = static_cast(_queue); + _isAsyncQueue = _glesQueue->isAsyncQueue(); +} + +void GLESCommandBuffer::doDestroy() { + waitFence(); +} + +void GLESCommandBuffer::waitFence() { + if (_fence->sync != nullptr) { + glesWaitFence(GLESDevice::getInstance(), _fence.get(), FENCE_WAIT_TIMEOUT, true); + glesDestroyFence(GLESDevice::getInstance(), _fence.get()); + _fence->sync = nullptr; + } +} + +const void *GLESCommandBuffer::copyOrAssignDataImpl(const void* ptr, uint32_t size) { + if (_isAsyncQueue && size > 0) { + auto *res = _storage->allocate(size); + memcpy(res, ptr, size); + return res; + } + return ptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.h b/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.h new file mode 100644 index 00000000000..384fc970342 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandBuffer.h @@ -0,0 +1,80 @@ +#pragma once + +#include "gfx-base/GFXCommandBuffer.h" +#include "gfx-gles-common/common/GLESCommandEncoder.h" +#include "gfx-gles-common/common/GLESCommandStorage.h" +#include "gfx-gles-common/common/GLESQueue.h" + +namespace cc::gfx { +class GLESQueue; + +class GLESCommandBuffer : public CommandBuffer { +public: + GLESCommandBuffer(); + ~GLESCommandBuffer() override; + + void begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) override; + void end() override; + void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) override; + void endRenderPass() override; + void bindPipelineState(PipelineState *pso) override; + void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) override; + void bindInputAssembler(InputAssembler *ia) override; + void setViewport(const Viewport &vp) override; + void setScissor(const Rect &rect) override; + void setLineWidth(float width) override; + void setDepthBias(float constant, float clamp, float slope) override; + void setBlendConstants(const Color &constants) override; + void setDepthBound(float minBounds, float maxBounds) override; + void setStencilWriteMask(StencilFace face, uint32_t mask) override; + void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) override; + void nextSubpass() override; + void draw(const DrawInfo &info) override; + void updateBuffer(Buffer *buff, const void *data, uint32_t size) override; + void copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) override; + void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) override; + void copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override; + void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override; + void execute(CommandBuffer *const *cmdBuffs, uint32_t count) override; + void dispatch(const DispatchInfo &info) override; + void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const * /*buffers*/, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const * /*textures*/, uint32_t textureBarrierCount) override; + void beginQuery(QueryPool *queryPool, uint32_t id) override; + void endQuery(QueryPool *queryPool, uint32_t id) override; + void resetQueryPool(QueryPool *queryPool) override; + + void attachContext(egl::Context *context); + void setTaskHandle(GLESQueue::TaskHandle handle); + void executeCommands(); +private: + friend class GLESDevice; + + void doInit(const CommandBufferInfo &info) override; + void doDestroy() override; + + const void *copyOrAssignDataImpl(const void *ptr, uint32_t size); + + template + const T *copyOrAssignData(const T *ptr, S count) { + return static_cast(copyOrAssignDataImpl(ptr, count * sizeof(T))); + } + + template + void enqueueCmd(Func &&func, Args &&...args) { + if (!_isAsyncQueue) { + std::invoke(std::forward(func), std::forward(args)...); + } else { + _storage->enqueueCmd(std::forward(func), std::forward(args)...); + } + } + + void waitFence(); + + GLESQueue::TaskHandle _lastTaskHandle = 0; + std::unique_ptr _fence; + std::unique_ptr _encoder; + std::unique_ptr _storage; + bool _isAsyncQueue = false; + GLESQueue *_glesQueue = nullptr; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandEncoder.h b/native/cocos/renderer/gfx-gles-common/common/GLESCommandEncoder.h new file mode 100644 index 00000000000..febe36846f1 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandEncoder.h @@ -0,0 +1,55 @@ +#pragma once + +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { +namespace egl { +class Context; +} // namespace egl + +struct PassBeginInfo { + GLESGPUFramebuffer *framebuffer = nullptr; + const Color *clearColors = nullptr; + float clearDepth = 1.F; + uint32_t clearStencil = 0; + Rect renderArea = {}; +}; + +struct DescriptorBindInfo { + GLESGPUDescriptorSet *descriptorSet = nullptr; + const uint32_t *dynamicOffsets = nullptr; + uint32_t dynamicCount = 0; +}; + +class GLESCommandEncoder { +public: + GLESCommandEncoder() = default; + virtual ~GLESCommandEncoder() = default; + + virtual void beginRenderPass(const PassBeginInfo &beginInfo) {} + virtual void endRenderPass() {} + virtual void nextSubPass() {} + virtual void bindPipelineState(GLESGPUPipelineState *pso) {} + virtual void bindDescriptorSet(uint32_t setID, const DescriptorBindInfo &bindInfo) {} + virtual void bindInputAssembler(GLESGPUInputAssembler *ia) {} + virtual void setViewport(const Viewport &vp) {} + virtual void setScissor(const Rect &rect) {} + virtual void setLineWidth(float width) {} + virtual void setDepthBias(float constant, float clamp, float slope) {} + virtual void setBlendConstants(const Color &constants) {} + virtual void setDepthBound(float minBounds, float maxBounds) {} + virtual void setStencilWriteMask(StencilFace face, uint32_t mask) {} + virtual void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) {} + virtual void draw(const DrawInfo &info) {} + virtual void drawIndirect() {} + virtual void drawIndexedIndirect() {} + virtual void dispatch(uint32_t x, uint32_t y, uint32_t z) {} + virtual void dispatchIndirect(GLESGPUBuffer *buffer, uint32_t offset) {} + virtual void updateBuffer(GLESGPUBuffer *buffer, const void *data, uint32_t size) {} + virtual void begin(GLESGPUFence *waitFence) {} + virtual void end(GLESGPUFence *signalFence) {} + + virtual void attachContext(egl::Context *context, GLESGPUStateCache *cacheState) {} +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp index 0e773f2b3de..eb4d2069c9e 100644 --- a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.cpp @@ -3,13 +3,16 @@ namespace cc::gfx { -uint8_t *GLESCommandStorage::BlockStorage::allocate(uint32_t size, uint32_t alignment) { - auto alignSize = utils::alignTo(size, alignment); +GLESCommandStorage::GLESCommandStorage() { + allocateStorage(); +} + +uint8_t *GLESCommandStorage::BlockStorage::allocate(uint32_t size) { if (!storage) { storage = std::make_unique(blockSize); } - if (offset + alignSize > blockSize) { + if (offset + size > blockSize) { return nullptr; } uint8_t *res = storage.get() + offset; @@ -29,6 +32,7 @@ void GLESCommandStorage::allocateStorage() { } void GLESCommandStorage::reset() { + _tmpBuffers.clear(); for (auto &storage : _storages) { storage->reset(); } @@ -47,13 +51,20 @@ void GLESCommandStorage::execute() { } uint8_t* GLESCommandStorage::allocate(uint32_t size, uint32_t alignment) { - uint8_t *ptr = (*_iterator)->allocate(size, alignment); + auto alignSize = utils::alignTo(size, alignment); + if (alignSize > DEFAULT_BLOCK_SIZE) { + _tmpBuffers.emplace_back(std::make_unique(alignSize)); + return _tmpBuffers.back().get(); + } + + uint8_t *ptr = (*_iterator)->allocate(alignSize); if (ptr == nullptr) { _iterator++; if (_iterator == _storages.end()) { allocateStorage(); } - ptr = (*_iterator)->allocate(size, alignment); + ptr = (*_iterator)->allocate(alignSize); + CC_ASSERT(ptr != nullptr); } return ptr; } diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h index 8d6b4199f9c..7e3018d1b67 100644 --- a/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommandStorage.h @@ -31,7 +31,7 @@ struct Cmd : public CmdBase { class GLESCommandStorage { public: - GLESCommandStorage() = default; + GLESCommandStorage(); ~GLESCommandStorage() = default; static constexpr uint32_t DEFAULT_ALIGNMENT = 4; @@ -57,13 +57,11 @@ class GLESCommandStorage { uint32_t offset = 0; std::unique_ptr storage; - uint8_t *allocate(uint32_t size, uint32_t alignment); + uint8_t *allocate(uint32_t size); void reset(); }; - -private: void allocateStorage(); - +private: using StoragePtr = std::unique_ptr; using Iterator = std::list::iterator; @@ -71,6 +69,7 @@ class GLESCommandStorage { Iterator _iterator = _storages.end(); CmdBase* _head = nullptr; CmdBase** _current = &_head; + ccstd::list> _tmpBuffers; }; } // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommands.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESCommands.cpp new file mode 100644 index 00000000000..e2f65065cd5 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommands.cpp @@ -0,0 +1,171 @@ +#include "GLESCommands.h" +#ifdef CC_USE_GLES2 +#include "gfx-gles-common/gles2/GLES2Commands.h" +#include "gfx-gles-common/gles2/GLES2CommandEncoder.h" +#endif +#ifdef CC_USE_GLES3 +#include "gfx-gles-common/gles3/GLES3Commands.h" +#include "gfx-gles-common/gles3/GLES3CommandEncoder.h" +#endif + +namespace cc::gfx { + +PFN_GLESUpdateFormatFeature glesUpdateFormatFeature; +PFN_GLESUpdateTextureExclusive glesUpdateTextureExclusive; +PFN_GLESUpdateFeatureAndCapabilities glesUpdateFeatureAndCapabilities; + +PFN_GLESCreateBuffer glesCreateBuffer; +PFN_GLESDestroyBuffer glesDestroyBuffer; +PFN_GLESResizeBuffer glesResizeBuffer; +PFN_GLESUpdateBuffer glesUpdateBuffer; + +PFN_GLESCreateTexture glesCreateTexture; +PFN_GLESDestroyTexture glesDestroyTexture; +PFN_GLESDestroyRenderBuffer glesDestroyRenderBuffer; +PFN_GLESResizeTexture glesResizeTexture; + +PFN_GLESUpdateProgramBinaryFormats glesUpdateProgramBinaryFormats; +PFN_GLESCreateShaderByBinary glesCreateShaderByBinary; +PFN_GLESCreateShaderBySource glesCreateShaderBySource; +PFN_GLESDestroyProgram glesDestroyProgram; + +PFN_GLESCreatePipelineState glesCreatePipelineState; +PFN_GLESDestroyPipelineState glesDestroyPipelineState; + + +PFN_GLESCreateRenderPass glesCreateRenderPass; + +PFN_GLESCreateInputAssembler glesCreateInputAssembler; +PFN_GLESDestroyInputAssembler glesDestroyInputAssembler; + +PFN_GLESCreateFramebuffer glesCreateFramebuffer; +PFN_GLESDestroyFramebuffer glesDestroyFramebuffer; + +PFN_GLESCreateSampler glesCreateSampler; +PFN_GLESDestroySampler glesDestroySampler; + +PFN_GLESCreateFence glesCreateFence; +PFN_GLESDestroyFence glesDestroyFence; +PFN_GLESWaitFence glesWaitFence; + +PFN_GLESCreateGeneralBarrier glesCreateGeneralBarrier; + +PFN_GLESCopyBuffersToTexture glesCopyBuffersToTexture; + +namespace { +#ifdef CC_USE_GLES2 +void initFunctionsV2() { + glesUpdateFormatFeature = cmdFuncGLES2UpdateFormatFeatures; + glesUpdateTextureExclusive = cmdFuncGLES2UpdateTextureExclusive; + glesUpdateFeatureAndCapabilities = cmdFuncGLES2UpdateFeatureAndCapabilities; + + glesCreateBuffer = cmdFuncGLES2CreateBuffer; + glesDestroyBuffer = cmdFuncGLES2DestroyBuffer; + glesResizeBuffer = cmdFuncGLES2ResizeBuffer; + glesUpdateBuffer = cmdFuncGLES2UpdateBuffer; + + glesCreateTexture = cmdFuncGLES2CreateTexture; + glesResizeTexture = cmdFuncGLES2ResizeTexture; + glesDestroyTexture = cmdFuncGLES2DestroyTexture; + glesDestroyRenderBuffer = cmdFuncGLES2DestroyRenderBuffer; + + glesUpdateProgramBinaryFormats = cmdFuncGLES2UpdateProgramBinaryFormats; + glesCreateShaderByBinary = cmdFuncGLES2CreateShaderByBinary; + glesCreateShaderBySource = cmdFuncGLES2CreateShaderBySource; + glesDestroyProgram = cmdFuncGLES2DestroyProgram; + + glesCreatePipelineState = cmdFuncGLES2CreatePipelineState; + glesDestroyPipelineState = cmdFuncGLES2DestroyPipelineState; + + glesCreateRenderPass = cmdFuncGLES2CreateRenderPass; + + glesCreateInputAssembler = cmdFuncGLES2CreateInputAssembler; + glesDestroyInputAssembler = cmdFuncGLES2DestroyInputAssembler; + + glesCreateFramebuffer = cmdFuncGLES2CreateFramebuffer; + glesDestroyFramebuffer = cmdFuncGLES2DestroyFramebuffer; + + glesCreateSampler = cmdFuncGLES2CreateSampler; + glesDestroySampler = cmdFuncGLES2DestroySampler; + + glesCreateFence = cmdFuncGLES2CreateFence; + glesDestroyFence = cmdFuncGLES2DestroyFence; + glesWaitFence = cmdFuncGLES2WaitFence; + + glesCreateGeneralBarrier = cmdFuncGLES2CreateGeneralBarrier; + + glesCopyBuffersToTexture = cmdFuncGLES2CopyBuffersToTexture; +} +#endif + +#ifdef CC_USE_GLES3 +void initFunctionsV3() { + glesUpdateFormatFeature = cmdFuncGLES3UpdateFormatFeatures; + glesUpdateTextureExclusive = cmdFuncGLES3UpdateTextureExclusive; + glesUpdateFeatureAndCapabilities = cmdFuncGLES3UpdateFeatureAndCapabilities; + + glesCreateBuffer = cmdFuncGLES3CreateBuffer; + glesDestroyBuffer = cmdFuncGLES3DestroyBuffer; + glesResizeBuffer = cmdFuncGLES3ResizeBuffer; + glesUpdateBuffer = cmdFuncGLES3UpdateBuffer; + + glesCreateTexture = cmdFuncGLES3CreateTexture; + glesResizeTexture = cmdFuncGLES3ResizeTexture; + glesDestroyTexture = cmdFuncGLES3DestroyTexture; + glesDestroyRenderBuffer = cmdFuncGLES3DestroyRenderBuffer; + + glesUpdateProgramBinaryFormats = cmdFuncGLES3UpdateProgramBinaryFormats; + glesCreateShaderByBinary = cmdFuncGLES3CreateShaderByBinary; + glesCreateShaderBySource = cmdFuncGLES3CreateShaderBySource; + glesDestroyProgram = cmdFuncGLES3DestroyProgram; + + glesCreatePipelineState = cmdFuncGLES3CreatePipelineState; + glesDestroyPipelineState = cmdFuncGLES3DestroyPipelineState; + + glesCreateRenderPass = cmdFuncGLES3CreateRenderPass; + + glesCreateInputAssembler = cmdFuncGLES3CreateInputAssembler; + glesDestroyInputAssembler = cmdFuncGLES3DestroyInputAssembler; + + glesCreateFramebuffer = cmdFuncGLES3CreateFramebuffer; + glesDestroyFramebuffer = cmdFuncGLES3DestroyFramebuffer; + + glesCreateSampler = cmdFuncGLES3CreateSampler; + glesDestroySampler = cmdFuncGLES3DestroySampler; + + glesCreateFence = cmdFuncGLES3CreateFence; + glesDestroyFence = cmdFuncGLES3DestroyFence; + glesWaitFence = cmdFuncGLES3WaitFence; + + glesCreateGeneralBarrier = cmdFuncGLES3CreateGeneralBarrier; + + glesCopyBuffersToTexture = cmdFuncGLES3CopyBuffersToTexture; +} +#endif +} // namespace + +void initGLESCmdFunctions(GLuint majorVersion) { +#ifdef CC_USE_GLES3 + if (majorVersion >= 3) { + initFunctionsV3(); + return; + } +#endif +#ifdef CC_USE_GLES2 + initFunctionsV2(); +#endif +} + +GLESCommandEncoder *createGLESCommandEncoder(GLuint majorVersion) { +#ifdef CC_USE_GLES3 + if (majorVersion >= 3) { + return ccnew GLES3CommandEncoder; + } +#endif +#ifdef CC_USE_GLES2 + return ccnew GLES2CommandEncoder; +#endif + return nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESCommands.h b/native/cocos/renderer/gfx-gles-common/common/GLESCommands.h new file mode 100644 index 00000000000..605cca160de --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESCommands.h @@ -0,0 +1,106 @@ +#pragma once + +#include "base/std/container/array.h" +#include "gfx-base/GFXDef-common.h" +#include "gfx-gles-common/common/GLESBase.h" +#include "gfx-gles-common/common/GLESCommandEncoder.h" + +namespace cc::gfx { +class GLESDevice; +struct GLESGPUBuffer; +struct GLESGPUTexture; +struct GLESGPUGeneralBarrier; +struct GLESGPUShader; +struct GLESGPUPipelineLayout; +struct GLESGPURenderPass; +struct GLESGPUInputAssembler; +struct GLESGPUFramebuffer; +struct GLESGPUSampler; +struct GLESGPUPipelineState; + +using PFN_GLESUpdateFormatFeature = void(*)(GLESDevice *device, ccstd::array(Format::COUNT)> &formatFeatures); +using PFN_GLESUpdateTextureExclusive = void(*)(GLESDevice *device, ccstd::array(Format::COUNT)> &textureExclusive); +using PFN_GLESUpdateFeatureAndCapabilities = void(*)(GLESDevice *device, DeviceCaps &caps, GLESGPUConstantRegistry &constantRegistry, ccstd::array(Feature::COUNT)> &features); + +using PFN_GLESCreateBuffer = void(*)(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +using PFN_GLESResizeBuffer = void(*)(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +using PFN_GLESUpdateBuffer = void(*)(GLESDevice *device, GLESGPUBuffer *gpuBuffer, const void *buffer, uint32_t offset, uint32_t size, bool mapBuffer, bool sync); +using PFN_GLESDestroyBuffer = void(*)(GLESDevice *device, GLuint *buffers, uint32_t count); + +using PFN_GLESCreateTexture = void(*)(GLESDevice *device, GLESGPUTexture *gpuTexture); +using PFN_GLESResizeTexture = void(*)(GLESDevice *device, GLESGPUTexture *gpuTexture); +using PFN_GLESDestroyTexture = void(*)(GLESDevice *device, GLuint *textures, uint32_t count); +using PFN_GLESDestroyRenderBuffer = void(*)(GLESDevice *device, GLuint *rbs, uint32_t count); + +using PFN_GLESUpdateProgramBinaryFormats = void(*)(GLESDevice *device, ccstd::vector &formats); +using PFN_GLESCreateShaderByBinary = void(*)(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +using PFN_GLESCreateShaderBySource = void(*)(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +using PFN_GLESDestroyProgram = void(*)(GLESDevice *device, GLuint programID); + +using PFN_GLESCreatePipelineState = void(*)(GLESDevice *device, GLESGPUPipelineState *gpuPso); +using PFN_GLESDestroyPipelineState = void(*)(GLESDevice *device, GLESGPUPipelineState *gpuPso); + +using PFN_GLESCreateRenderPass = void(*)(GLESDevice *device, GLESGPURenderPass *gpuRenderPass); + +using PFN_GLESCreateInputAssembler = void(*)(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); +using PFN_GLESDestroyInputAssembler = void(*)(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); + +using PFN_GLESCreateFramebuffer = void(*)(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); +using PFN_GLESDestroyFramebuffer = void(*)(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); + +using PFN_GLESCreateSampler = void(*)(GLESDevice *device, GLESGPUSampler *gpuSampler); +using PFN_GLESDestroySampler = void(*)(GLESDevice *device, GLESGPUSampler *gpuSampler); + +using PFN_GLESCreateFence = void(*)(GLESDevice *device, GLESGPUFence *gpuFence); +using PFN_GLESDestroyFence = void(*)(GLESDevice *device, GLESGPUFence *gpuFence); +using PFN_GLESWaitFence = void(*)(GLESDevice *device, GLESGPUFence *gpuFence, uint64_t timeout, bool isClient); + +using PFN_GLESCreateGeneralBarrier = void(*)(GLESDevice *device, GLESGPUGeneralBarrier *barrier); + +using PFN_GLESCopyBuffersToTexture = void(*)(GLESDevice *device, const uint8_t *const *buffers, GLESGPUTexture *gpuTexture, const BufferTextureCopy *regions, uint32_t count); + +extern PFN_GLESUpdateFormatFeature glesUpdateFormatFeature; +extern PFN_GLESUpdateTextureExclusive glesUpdateTextureExclusive; +extern PFN_GLESUpdateFeatureAndCapabilities glesUpdateFeatureAndCapabilities; + +extern PFN_GLESCreateBuffer glesCreateBuffer; +extern PFN_GLESDestroyBuffer glesDestroyBuffer; +extern PFN_GLESResizeBuffer glesResizeBuffer; +extern PFN_GLESUpdateBuffer glesUpdateBuffer; + +extern PFN_GLESCreateTexture glesCreateTexture; +extern PFN_GLESDestroyTexture glesDestroyTexture; +extern PFN_GLESDestroyRenderBuffer glesDestroyRenderBuffer; +extern PFN_GLESResizeTexture glesResizeTexture; + +extern PFN_GLESUpdateProgramBinaryFormats glesUpdateProgramBinaryFormats; +extern PFN_GLESCreateShaderByBinary glesCreateShaderByBinary; +extern PFN_GLESCreateShaderBySource glesCreateShaderBySource; +extern PFN_GLESDestroyProgram glesDestroyProgram; + +extern PFN_GLESCreatePipelineState glesCreatePipelineState; +extern PFN_GLESDestroyPipelineState glesDestroyPipelineState; + +extern PFN_GLESCreateRenderPass glesCreateRenderPass; + +extern PFN_GLESCreateInputAssembler glesCreateInputAssembler; +extern PFN_GLESDestroyInputAssembler glesDestroyInputAssembler; + +extern PFN_GLESCreateFramebuffer glesCreateFramebuffer; +extern PFN_GLESDestroyFramebuffer glesDestroyFramebuffer; + +extern PFN_GLESCreateSampler glesCreateSampler; +extern PFN_GLESDestroySampler glesDestroySampler; + +extern PFN_GLESCreateFence glesCreateFence; +extern PFN_GLESDestroyFence glesDestroyFence; +extern PFN_GLESWaitFence glesWaitFence; + +extern PFN_GLESCreateGeneralBarrier glesCreateGeneralBarrier; + +extern PFN_GLESCopyBuffersToTexture glesCopyBuffersToTexture; + +void initGLESCmdFunctions(GLuint majorVersion); +GLESCommandEncoder *createGLESCommandEncoder(GLuint majorVersion); + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.cpp new file mode 100644 index 00000000000..72cd365d1bc --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.cpp @@ -0,0 +1,74 @@ +#include "GLESDescriptorSet.h" +#include "GLESDescriptorSetLayout.h" +#include "GLESBuffer.h" +#include "GLESTexture.h" +#include "GLESSampler.h" +#include "GLESDevice.h" + +namespace cc::gfx { + +GLESDescriptorSet::GLESDescriptorSet() { + _typedID = generateObjectID(); +} + +GLESDescriptorSet::~GLESDescriptorSet() { + destroy(); +} + +void GLESDescriptorSet::update() { + if (!_isDirty || !_gpuDescriptorSet) { + return; + } + + auto *device = Device::getInstance(); + auto &descriptors = _gpuDescriptorSet->gpuDescriptors; + for (size_t i = 0; i < descriptors.size(); i++) { + if (hasAnyFlags(descriptors[i].type, DESCRIPTOR_BUFFER_TYPE)) { + if (_buffers[i].ptr) { + descriptors[i].gpuBufferView = static_cast(_buffers[i].ptr)->gpuBufferView(); + } + } else if (hasAnyFlags(descriptors[i].type, DESCRIPTOR_TEXTURE_TYPE)) { + descriptors[i].gpuSampler = _samplers[i].ptr ? static_cast(_samplers[i].ptr)->gpuSampler() + : static_cast(device->getSampler({}))->gpuSampler(); + if (_textures[i].ptr) { + _gpuDescriptorSet->gpuDescriptors[i].gpuTextureView = static_cast(_textures[i].ptr)->gpuTextureView(); + + // work around for sample depth stencil texture, delete when rdg support set sampler. + const FormatInfo &info = GFX_FORMAT_INFOS[toNumber( + _textures[i].ptr->getFormat())]; + if (info.hasDepth || info.hasStencil) { + gfx::SamplerInfo samplerInfo = {}; + samplerInfo.minFilter = gfx::Filter::POINT; + samplerInfo.magFilter = gfx::Filter::POINT; + descriptors[i].gpuSampler = static_cast(device->getSampler(samplerInfo))->gpuSampler(); + } + } + } + } + _isDirty = false; +} + +void GLESDescriptorSet::forceUpdate() { + update(); +} + +void GLESDescriptorSet::doInit(const DescriptorSetInfo & /*info*/) { + const GLESGPUDescriptorSetLayout *gpuDescriptorSetLayout = static_cast(_layout)->gpuDescriptorSetLayout(); + const size_t descriptorCount = gpuDescriptorSetLayout->descriptorCount; + const size_t bindingCount = gpuDescriptorSetLayout->bindings.size(); + + _gpuDescriptorSet = ccnew GLESGPUDescriptorSet; + _gpuDescriptorSet->layout = gpuDescriptorSetLayout; + _gpuDescriptorSet->gpuDescriptors.resize(descriptorCount); + for (size_t i = 0U, k = 0U; i < bindingCount; i++) { + const auto &binding = gpuDescriptorSetLayout->bindings[i]; + for (uint32_t j = 0; j < binding.count; j++, k++) { + _gpuDescriptorSet->gpuDescriptors[k].type = binding.type; + } + } +} + +void GLESDescriptorSet::doDestroy() { + _gpuDescriptorSet = nullptr; +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.h b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.h new file mode 100644 index 00000000000..effa5fb5db6 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSet.h @@ -0,0 +1,25 @@ +#pragma once + +#include "gfx-base/GFXDescriptorSet.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESDescriptorSet final : public DescriptorSet { +public: + GLESDescriptorSet(); + ~GLESDescriptorSet() override; + + GLESGPUDescriptorSet *gpuDescriptorSet() const { return _gpuDescriptorSet; } + + void update() override; + void forceUpdate() override; + +protected: + void doInit(const DescriptorSetInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuDescriptorSet; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.cpp new file mode 100644 index 00000000000..ae2711840ac --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.cpp @@ -0,0 +1,40 @@ +#include "GLESDescriptorSetLayout.h" +#include "GLESSampler.h" + +namespace cc::gfx { + +GLESDescriptorSetLayout::GLESDescriptorSetLayout() { + _typedID = generateObjectID(); +} + +GLESDescriptorSetLayout::~GLESDescriptorSetLayout() { + destroy(); +} + +void GLESDescriptorSetLayout::doInit(const DescriptorSetLayoutInfo & /*info*/) { + _gpuDescriptorSetLayout = ccnew GLESGPUDescriptorSetLayout; + _gpuDescriptorSetLayout->bindings.reserve(_bindings.size()); + _gpuDescriptorSetLayout->descriptorCount = _descriptorCount; + auto &hash = _gpuDescriptorSetLayout->hash; + + for (auto &binding : _bindings) { + _gpuDescriptorSetLayout->bindings.emplace_back(); + auto &back = _gpuDescriptorSetLayout->bindings.back(); + back.binding = binding.binding; + back.count = binding.count; + back.type = binding.descriptorType; + + ccstd::hash_combine(hash, binding.binding); + ccstd::hash_combine(hash, binding.descriptorType); + ccstd::hash_combine(hash, binding.count); + ccstd::hash_combine(hash, binding.stageFlags); + for (auto &sampler : binding.immutableSamplers) { + ccstd::hash_combine(hash, sampler->getHash()); + } + } +} + +void GLESDescriptorSetLayout::doDestroy() { + _gpuDescriptorSetLayout = nullptr; +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.h b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.h new file mode 100644 index 00000000000..e40bf08aa0a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDescriptorSetLayout.h @@ -0,0 +1,22 @@ +#pragma once + +#include "gfx-base/GFXDescriptorSetLayout.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESDescriptorSetLayout final : public DescriptorSetLayout { +public: + GLESDescriptorSetLayout(); + ~GLESDescriptorSetLayout() override; + + GLESGPUDescriptorSetLayout *gpuDescriptorSetLayout() const { return _gpuDescriptorSetLayout; } + +protected: + void doInit(const DescriptorSetLayoutInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuDescriptorSetLayout; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDevice.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESDevice.cpp new file mode 100644 index 00000000000..64f02225921 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDevice.cpp @@ -0,0 +1,283 @@ +#include "GLESDevice.h" +#include "base/StringUtil.h" +#include "gfx-gles-common/egl/Instance.h" +#include "GLESBuffer.h" +#include "GLESCommandBuffer.h" +#include "GLESDescriptorSet.h" +#include "GLESDescriptorSetLayout.h" +#include "GLESFramebuffer.h" +#include "GLESInputAssembler.h" +#include "GLESPipelineLayout.h" +#include "GLESPipelineState.h" +#include "GLESRenderPass.h" +#include "GLESSampler.h" +#include "GLESShader.h" +#include "GLESSwapchain.h" +#include "GLESTexture.h" + +namespace cc::gfx { +static constexpr bool ENABLE_ASYNC_CONTEXT = true; + +GLESDevice *GLESDevice::instance = nullptr; +GLESDevice *GLESDevice::getInstance() { + return GLESDevice::instance; +} + +GLESDevice::~GLESDevice() { + GLESDevice::instance = nullptr; +} + +GLESDevice::GLESDevice() { + GLESDevice::instance = this; +} + +bool GLESDevice::initContext(EGLint majorVersion) { + egl::ContextInfo info = {}; + info.majorVersion = majorVersion; + + uint32_t contextID = 0; + _mainContext = std::make_unique(contextID++); + if (!_mainContext->init(info)) { + return false; + } + if (_mainContext->getMajorVersion() < 3) { + _api = API::GLES2; + _deviceName = "GLES2"; + } else { + _api = API::GLES3; + _deviceName = "GLES3"; + } + + QueueInfo queueInfo = {}; + _graphicsQueue = ccnew GLESQueue(); + _graphicsQueue->initialize(queueInfo); + + _queue = _graphicsQueue.get(); + _queues[toNumber(QueueType::GRAPHICS)] = _graphicsQueue.get(); + _queues[toNumber(QueueType::COMPUTE)] = _graphicsQueue.get(); + _queues[toNumber(QueueType::TRANSFER)] = _graphicsQueue.get(); + + if (ENABLE_ASYNC_CONTEXT) { + /** + * 3 context, 2 async queue + * mainContext(logic thread) + * graphicsContext(Queue with thread1): for render commands encode + * asyncContext(Queue with thread2): for transfer commands + */ + info.sharedContext = _mainContext->getContext(); + + // main context + _mainContext->makeCurrent(); + + // init async queue + queueInfo.type = QueueType::TRANSFER; + _asyncQueue = ccnew GLESQueue(); + _asyncQueue->initialize(queueInfo); + + // init graphics queue context + _graphicsContext = std::make_unique(contextID++); + _graphicsContext->init(info); + _graphicsQueue->startThread(); + _graphicsQueue->initContext(_graphicsContext.get()); + + // init async queue context + memset(&info.config, 0, sizeof(egl::Config)); + _asyncContext = std::make_unique(contextID++); + _asyncContext->init(info); + _asyncQueue->startThread(); + _asyncQueue->initContext(_asyncContext.get()); + + _queues[toNumber(QueueType::TRANSFER)] = _asyncQueue.get(); + } else { + /** + * 1 context, 1 queue + * mainContext(logic thread) + */ + _graphicsQueue->initContext(_mainContext.get()); + } + _cacheStates.resize(contextID); + for (uint32_t i = 0; i < contextID; ++i) { + _cacheStates[i].reset(ccnew GLESGPUStateCache); + } + + _renderer = reinterpret_cast(glGetString(GL_RENDERER)); + _vendor = reinterpret_cast(glGetString(GL_VENDOR)); + _version = reinterpret_cast(glGetString(GL_VERSION)); + _extensions = StringUtil::split(reinterpret_cast(glGetString(GL_EXTENSIONS)), " "); + + initGLESCmdFunctions(_mainContext->getMajorVersion()); + + CommandBufferInfo cmdBuffInfo; + cmdBuffInfo.type = CommandBufferType::PRIMARY; + cmdBuffInfo.queue = _queue; + _cmdBuff = createCommandBuffer(cmdBuffInfo); + return true; +} + +void GLESDevice::initDeviceFeaturesAndConstants() { + glesUpdateFormatFeature(this, _formatFeatures); + glesUpdateTextureExclusive(this, _textureExclusive); + glesUpdateFeatureAndCapabilities(this, _caps, _gpuConstantRegistry, _features); + + CC_LOG_INFO("GLES3 device initialized."); + CC_LOG_INFO("RENDERER: %s", _renderer.c_str()); + CC_LOG_INFO("VENDOR: %s", _vendor.c_str()); + CC_LOG_INFO("VERSION: %s", _version.c_str()); + CC_LOG_INFO("COMPRESSED_FORMATS: %s", _gpuConstantRegistry.compressedFmts.c_str()); + CC_LOG_INFO("FRAMEBUFFER_FETCH: %s", _gpuConstantRegistry.fbfLevelStr.c_str()); + CC_LOG_INFO("MULTI_SAMPLE_RENDER_TO_TEXTURE: %s", _gpuConstantRegistry.msaaLevelStr.c_str()); +} + +void GLESDevice::initDefaultObject() { + +} + +void GLESDevice::frameSync() { + +} + +void GLESDevice::acquire(gfx::Swapchain *const *swapchains, uint32_t count) { + _currentSwapChains.clear(); + for (uint32_t i = 0; i < count; ++i) { + _currentSwapChains.push_back(static_cast(swapchains[i])); + } +} + +void GLESDevice::present() { + for (auto *swapchain : _currentSwapChains) { + IntrusivePtr const surface = swapchain->gpuSwapchain()->surface; + _graphicsQueue->queueTask([=]() { + surface->swapBuffer(); + }); + } + + _frameIndex = (_frameIndex + 1) % _maxFrame; + _recycleBins[_frameIndex]->clear(); + _stagingStorages[_frameIndex]->reset(); +} + +void GLESDevice::copyBuffersToTexture(const uint8_t *const *buffers, gfx::Texture *dst, const BufferTextureCopy *regions, uint32_t count) { + glesCopyBuffersToTexture(GLESDevice::getInstance(), buffers, static_cast(dst)->gpuTexture(), regions, count); +} + +void GLESDevice::copyTextureToBuffers(gfx::Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) { + +} + +void GLESDevice::waitIdle() { + _graphicsQueue->waitIdle(); + if (_asyncQueue) { + _asyncQueue->waitIdle(); + } +} + +bool GLESDevice::doInit(const DeviceInfo & /*info*/) { + if (!egl::Instance::initialize()) { + return false; + } + +#ifdef CC_USE_GLES3 + if (!initContext(3)) { + return false; + } +#endif +#ifdef CC_USE_GLES2 + if (!_mainContext && !initContext(2)) { + return false; + } +#endif + + initDeviceFeaturesAndConstants(); + initDefaultObject(); + +#if CC_USE_PIPELINE_CACHE + _pipelineCache = std::make_unique(); + _pipelineCache->init(); +#endif + for (uint32_t i = 0; i < MAX_FRAME; ++i) { + _recycleBins[i] = std::make_unique(); + _stagingStorages[i] = std::make_unique(); + } + + return true; +} + +void GLESDevice::doDestroy() { + _mainContext = nullptr; + _graphicsContext = nullptr; + _asyncContext = nullptr; + _graphicsQueue = nullptr; + _asyncQueue = nullptr; + _defaultCmdBuffer = nullptr; + _pipelineCache = nullptr; + + _cmdBuff = nullptr; + _queue = nullptr; + egl::Instance::shutdown(); +} + +CommandBuffer *GLESDevice::createCommandBuffer(const CommandBufferInfo & /*info*/, bool /*hasAgent*/) { + return ccnew GLESCommandBuffer; +} + +Queue *GLESDevice::createQueue() { + return nullptr; +} + +QueryPool *GLESDevice::createQueryPool() { + return nullptr; +} + +Swapchain *GLESDevice::createSwapchain() { + return ccnew GLESSwapchain; +} + +Buffer *GLESDevice::createBuffer() { + return ccnew GLESBuffer; +} + +Texture *GLESDevice::createTexture() { + return ccnew GLESTexture; +} + +Shader *GLESDevice::createShader() { + return ccnew GLESShader; +} + +InputAssembler *GLESDevice::createInputAssembler() { + return ccnew GLESInputAssembler; +} + +RenderPass *GLESDevice::createRenderPass() { + return ccnew GLESRenderPass; +} + +Framebuffer *GLESDevice::createFramebuffer() { + return ccnew GLESFramebuffer; +} + +DescriptorSet *GLESDevice::createDescriptorSet() { + return ccnew GLESDescriptorSet; +} + +DescriptorSetLayout *GLESDevice::createDescriptorSetLayout() { + return ccnew GLESDescriptorSetLayout; +} + +PipelineLayout *GLESDevice::createPipelineLayout() { + return ccnew GLESPipelineLayout; +} + +PipelineState *GLESDevice::createPipelineState() { + return ccnew GLESPipelineState; +} + +Sampler *GLESDevice::createSampler(const SamplerInfo &info) { + return ccnew GLESSampler(info); +} + +GeneralBarrier *GLESDevice::createGeneralBarrier(const GeneralBarrierInfo &info) { + return ccnew GeneralBarrier(info); +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESDevice.h b/native/cocos/renderer/gfx-gles-common/common/GLESDevice.h new file mode 100644 index 00000000000..9c8e752300f --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESDevice.h @@ -0,0 +1,147 @@ +#pragma once + +#include "gfx-base/GFXDevice.h" +#include "gfx-gles-common/common/GLESBase.h" +#include "gfx-gles-common/common/GLESQueue.h" +#include "gfx-gles-common/common/GLESSwapchain.h" +#include "gfx-gles-common/common/GLESCommands.h" +#include "gfx-gles-common/common/GLESPipelineCache.h" +#include "gfx-gles-common/common/GLESRecycleBin.h" +#include "gfx-gles-common/common/GLESCommandStorage.h" +#include "gfx-gles-common/egl/Context.h" + +namespace cc::gfx { +class GLESDevice : public Device { +public: + ~GLESDevice() override; + + static GLESDevice *getInstance(); + + using gfx::Device::copyBuffersToTexture; + using gfx::Device::createBuffer; + using gfx::Device::createCommandBuffer; + using gfx::Device::createDescriptorSet; + using gfx::Device::createDescriptorSetLayout; + using gfx::Device::createFramebuffer; + using gfx::Device::createGeneralBarrier; + using gfx::Device::createInputAssembler; + using gfx::Device::createPipelineLayout; + using gfx::Device::createPipelineState; + using gfx::Device::createQueryPool; + using gfx::Device::createQueue; + using gfx::Device::createRenderPass; + using gfx::Device::createSampler; + using gfx::Device::createShader; + using gfx::Device::createSwapchain; + using gfx::Device::createTexture; + using gfx::Device::createTextureBarrier; + + void frameSync() override; + + // swapchain + void acquire(gfx::Swapchain *const *swapchains, uint32_t count) override; + void present() override; + + // copy + void copyBuffersToTexture(const uint8_t *const *buffers, gfx::Texture *dst, const BufferTextureCopy *regions, uint32_t count) override; + void copyTextureToBuffers(gfx::Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) override; + void getQueryPoolResults(QueryPool *queryPool) override {} + + // status + void waitIdle(); + + // context + egl::Context *getMainContext() const { return _mainContext.get(); } + GLESQueue *getQueue(QueueType type) const { return _queues[toNumber(type)]; } + GLESGPUStateCache *getCacheState(uint32_t contextID) const { return _cacheStates[contextID].get(); } + + // pipeline cache + GLESPipelineCache *pipelineCache() const { return _pipelineCache.get(); } + GLESRecycleBin *recycleBin() const { return _recycleBins[_frameIndex].get(); } + GLESCommandStorage *stagingBuffer() const { return _stagingStorages[_frameIndex].get(); } + + const GLESGPUConstantRegistry &constantRegistry() const { return _gpuConstantRegistry; } + + inline bool checkExtension(const ccstd::string &extension) const { + return std::any_of(_extensions.begin(), _extensions.end(), [&extension](auto &ext) { + return ext.find(extension) != ccstd::string::npos; + }); + } + inline bool isTextureExclusive(const Format &format) const { return _textureExclusive[static_cast(format)]; }; + + template + void forEachContext(Func &&fn) { + fn(_mainContext.get()); + if (_graphicsContext) { + _graphicsQueue->queueTaskInternal([=]() { + fn(_graphicsContext.get()); + }); + } + if (_asyncContext) { + _asyncQueue->queueTaskInternal([=]() { + fn(_asyncContext.get()); + }); + } + } + + uint32_t currentFrameIndex() const { return _frameIndex; } + uint32_t maxFrameInFlight() const { return _maxFrame; } +private: + friend class DeviceManager; + GLESDevice(); + + static GLESDevice *instance; + static constexpr uint32_t MAX_FRAME = 2; + + bool doInit(const DeviceInfo &info) override; + void doDestroy() override; + // create device object + + gfx::CommandBuffer *createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) override; + gfx::Queue *createQueue() override; + gfx::QueryPool *createQueryPool() override; + gfx::Swapchain *createSwapchain() override; + gfx::Buffer *createBuffer() override; + gfx::Texture *createTexture() override; + gfx::Shader *createShader() override; + gfx::InputAssembler *createInputAssembler() override; + gfx::RenderPass *createRenderPass() override; + gfx::Framebuffer *createFramebuffer() override; + gfx::DescriptorSet *createDescriptorSet() override; + gfx::DescriptorSetLayout *createDescriptorSetLayout() override; + gfx::PipelineLayout *createPipelineLayout() override; + gfx::PipelineState *createPipelineState() override; + gfx::Sampler *createSampler(const SamplerInfo &info) override; + gfx::GeneralBarrier *createGeneralBarrier(const GeneralBarrierInfo &info) override; + + + bool initContext(EGLint majorVersion); + void initDefaultObject(); + void initDeviceFeaturesAndConstants(); + + ccstd::vector _extensions; + ccstd::array(Format::COUNT)> _textureExclusive; + + std::unique_ptr _mainContext; + std::unique_ptr _graphicsContext; + std::unique_ptr _asyncContext; + + std::unique_ptr _pipelineCache; + ccstd::array, MAX_FRAME> _stagingStorages; + ccstd::array, MAX_FRAME> _recycleBins; + + GLESQueue *_queues[QUEUE_NUM]{nullptr}; + ccstd::vector> _cacheStates; // per context + + IntrusivePtr _graphicsQueue; + IntrusivePtr _asyncQueue; + IntrusivePtr _defaultCmdBuffer; + + GLESGPUConstantRegistry _gpuConstantRegistry; + // frame context + uint32_t _frameIndex = 0; + uint32_t _maxFrame = MAX_FRAME; + ccstd::vector _currentSwapChains; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.cpp new file mode 100644 index 00000000000..a6158b06ed7 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.cpp @@ -0,0 +1,58 @@ +#include "GLESFramebuffer.h" +#include "GLESTexture.h" +#include "GLESRenderPass.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +GLESFramebuffer::GLESFramebuffer() { + _typedID = generateObjectID(); +} + +GLESFramebuffer::~GLESFramebuffer() { + destroy(); +} + +void GLESFramebuffer::updateExtent() { + if (!_colorTextures.empty()) { + const auto *tex = _colorTextures[0]; + _gpuFBO->width = tex->getWidth(); + _gpuFBO->height = tex->getHeight(); + return; + } + if (_depthStencilTexture != nullptr) { + _gpuFBO->width = _depthStencilTexture->getWidth(); + _gpuFBO->height = _depthStencilTexture->getHeight(); + return; + } +} + +void GLESFramebuffer::doInit(const FramebufferInfo & /*info*/) { + _gpuFBO = ccnew GLESGPUFramebuffer; + updateExtent(); + + _gpuFBO->gpuRenderPass = static_cast(_renderPass)->gpuRenderPass(); + _gpuFBO->gpuColorViews.resize(_colorTextures.size()); + for (size_t i = 0; i < _colorTextures.size(); ++i) { + auto *colorTexture = static_cast(_colorTextures.at(i)); + _gpuFBO->gpuColorViews[i] = colorTexture->gpuTextureView(); + } + + if (_depthStencilTexture) { + auto *depthTexture = static_cast(_depthStencilTexture); + _gpuFBO->gpuDepthStencilView = depthTexture->gpuTextureView(); + } + + if (_depthStencilResolveTexture) { + auto *depthTexture = static_cast(_depthStencilResolveTexture); + _gpuFBO->gpuDepthStencilResolveView = depthTexture->gpuTextureView(); + } + glesCreateFramebuffer(GLESDevice::getInstance(), _gpuFBO, 0); +} + +void GLESFramebuffer::doDestroy() { + _gpuFBO = nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.h b/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.h new file mode 100644 index 00000000000..e3e9ea244e2 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESFramebuffer.h @@ -0,0 +1,23 @@ +#pragma once + +#include "gfx-base/GFXFramebuffer.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESFramebuffer final : public Framebuffer { +public: + GLESFramebuffer(); + ~GLESFramebuffer() override; + + GLESGPUFramebuffer *gpuFramebuffer() const { return _gpuFBO.get(); } + +protected: + void doInit(const FramebufferInfo &info) override; + void doDestroy() override; + void updateExtent(); + + IntrusivePtr _gpuFBO; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESGPUObjects.h b/native/cocos/renderer/gfx-gles-common/common/GLESGPUObjects.h new file mode 100644 index 00000000000..8e55d70e596 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESGPUObjects.h @@ -0,0 +1,303 @@ +#pragma once + +#include +#include "base/Ptr.h" +#include "gfx-base/GFXDeviceObject.h" +#include "gfx-gles-common/egl/Surface.h" +#include "gfx-gles-common/common/GLESBase.h" + +namespace cc::gfx { + +struct GLESGPUBuffer : public GFXDeviceObject { + GLESGPUBuffer() = default; + ~GLESGPUBuffer() override; + + BufferUsage usage = BufferUsage::NONE; + MemoryUsage memUsage = MemoryUsage::NONE; + uint32_t size = 0; + GLuint glBuffer = 0; + GLenum glUsage = 0; + uint32_t lastUpdateFrame = (~0U); + std::unique_ptr buffer; +}; + +struct GLESGPUBufferView : public GFXDeviceObject { + IntrusivePtr gpuBuffer; + GLuint offset = 0; + GLuint range = 0; + uint32_t stride = 0; +}; + +using GLESGPUBufferViewList = ccstd::vector>; + +struct GLESGPUSwapchain; +struct GLESGPUTexture : public GFXDeviceObject { + GLESGPUTexture() = default; + ~GLESGPUTexture() override; + + TextureType type{TextureType::TEX2D}; + Format format{Format::UNKNOWN}; + TextureUsage usage{TextureUsageBit::NONE}; + uint32_t width{0}; + uint32_t height{0}; + uint32_t depth{1}; + uint32_t size{0}; + uint32_t arrayLayer{1}; + uint32_t mipLevel{1}; + TextureFlags flags{TextureFlagBit::NONE}; + + bool immutable{true}; + bool isPowerOf2{false}; + bool useRenderBuffer{false}; + bool memoryAllocated{true}; // false if swapchain image or implicit ms render buffer. + + GLenum glInternalFmt{0}; + GLenum glFormat{0}; + GLenum glType{0}; + GLenum glUsage{0}; + GLint glSamples{0}; + GLuint glTexture{0}; + GLuint glRenderbuffer{0}; + GLenum glTarget = GL_NONE; + + // for gles2 + GLenum glWrapS{0}; + GLenum glWrapT{0}; + GLenum glMinFilter{0}; + GLenum glMagFilter{0}; + + GLESGPUSwapchain *swapchain{nullptr}; +}; + +struct GLESGPUTextureView : public GFXDeviceObject { + IntrusivePtr texture; + TextureType type = TextureType::TEX2D; + Format format = Format::UNKNOWN; + uint32_t baseLevel = 0U; + uint32_t levelCount = 1U; + uint32_t baseLayer = 0U; + uint32_t layerCount = 1U; +}; +using GLESGPUTextureViewList = ccstd::vector>; + +struct GLESGPUSwapchain : public GFXDeviceObject { +#if CC_SWAPPY_ENABLED + bool swappyEnabled{false}; +#endif + IntrusivePtr surface; + EGLint eglSwapInterval{0}; + IntrusivePtr gpuColorTexture; +}; + +struct GLESGPUSampler : public GFXDeviceObject { + GLESGPUSampler() = default; + ~GLESGPUSampler() override; + + Filter minFilter = Filter::NONE; + Filter magFilter = Filter::NONE; + Filter mipFilter = Filter::NONE; + Address addressU = Address::CLAMP; + Address addressV = Address::CLAMP; + Address addressW = Address::CLAMP; + + GLenum glMinFilter = 0; + GLenum glMagFilter = 0; + GLenum glWrapS = 0; + GLenum glWrapT = 0; + GLenum glWrapR = 0; + + float minLod = 0.F; + float maxLod = 16.F; + + GLuint glSampler = 0; +}; + +using DrawBuffer = ccstd::vector; +struct GLESGPURenderPass : public GFXDeviceObject { + ColorAttachmentList colorAttachments; + DepthStencilAttachment depthStencilAttachment; + DepthStencilAttachment depthStencilResolveAttachment; + SubpassInfoList subpasses; + SubpassDependencyList dependencies; + + ccstd::vector colors; + ccstd::vector resolves; + uint32_t depthStencil = INVALID_BINDING; + uint32_t depthStencilResolve = INVALID_BINDING; + ccstd::vector indices; // offsets to GL_COLOR_ATTACHMENT_0 + ccstd::vector drawBuffers; +}; + +struct GLESGPUAttribute { + ccstd::string name; + GLuint glBuffer = 0; + GLenum glType = 0; + uint32_t size = 0; + uint32_t count = 0; + uint32_t stride = 1; + uint32_t componentCount = 1; + bool isNormalized = false; + bool isInstanced = false; + uint32_t offset = 0; +}; +using GLESGPUAttributeList = ccstd::vector; + +struct GLESGPUInputAssembler : public GFXDeviceObject { + GLESGPUInputAssembler() = default; + ~GLESGPUInputAssembler() override = default; + + // vao can not be shared cross context. + using VAOList = ccstd::array; + using VAOMap = ccstd::unordered_map; + VAOMap vaoMap; + + AttributeList attributes; + GLESGPUAttributeList glAttribs; + + GLESGPUBufferViewList gpuVertexBuffers; + IntrusivePtr gpuIndexBuffer; + IntrusivePtr gpuIndirectBuffer; // deprecated future. + GLenum glIndexType = 0; +}; + +struct GLESGPUSwapchain; +struct GLESGPUFramebufferObject { + using Reference = std::pair, GLint>; + + GLuint handle[MAX_CONTEXT_NUM]{0}; // fbo can not be shared cross context. + GLESGPUSwapchain *swapchain{nullptr}; // weak reference + + ccstd::vector colors; + Reference depthStencil{nullptr, 1}; + GLenum dsAttachment{GL_NONE}; + + ccstd::vector loadInvalidates; + ccstd::vector storeInvalidates; +}; + +struct GLESGPUFramebuffer : public GFXDeviceObject { + GLESGPUFramebuffer() = default; + ~GLESGPUFramebuffer() override = default; + + ConstPtr gpuRenderPass; + GLESGPUTextureViewList gpuColorViews; + ConstPtr gpuDepthStencilView; + ConstPtr gpuDepthStencilResolveView; + + uint32_t width{UINT_MAX}; + uint32_t height{UINT_MAX}; + bool needResolve = false; + GLbitfield dsResolveMask = 0; + std::vector> colorBlitPairs; + GLESGPUFramebufferObject framebuffer; + GLESGPUFramebufferObject resolveFramebuffer; +}; + +struct GLESGPUBinding { + DescriptorType type = DescriptorType::UNKNOWN; + uint32_t binding = 0; // current binding + uint32_t count = 0; // current descriptor count +}; + +struct GLESGPUDescriptorSetLayout : public GFXDeviceObject { + ccstd::vector bindings; + uint32_t descriptorCount = 0U; // quick look at descriptor count; + ccstd::hash_t hash = 0U; +}; + +struct GLESGPUPipelineLayout : public GFXDeviceObject { + ccstd::vector> setLayouts; + uint32_t descriptorCount = 0; + ccstd::hash_t hash = 0U; +}; + +struct GLESGPUDescriptor { + DescriptorType type = DescriptorType::UNKNOWN; + IntrusivePtr gpuBufferView; + IntrusivePtr gpuTextureView; + IntrusivePtr gpuSampler; +}; +using GLESGPUDescriptorList = ccstd::vector; +struct GLESGPUDescriptorSet : public GFXDeviceObject { + GLESGPUDescriptorList gpuDescriptors; + ConstPtr layout; +}; + +struct GLESGPUInput { + ccstd::string name; + GLsizei glLength = 0; + GLint glSize = 0; + GLenum glType = 0; + GLint glLoc = -1; +}; + +struct GLESGPUShader : public GFXDeviceObject { + GLESGPUShader() = default; + ~GLESGPUShader() override; + + struct Stage { + ccstd::string source; + ShaderStageFlagBit type; + GLuint glShader; + }; + ccstd::string name; + ccstd::vector stages; + GLuint glProgram = 0; + ccstd::hash_t hash = INVALID_SHADER_HASH; + + UniformBlockList blocks; + UniformStorageBufferList buffers; + UniformSamplerTextureList samplerTextures; + UniformStorageImageList images; +}; + +struct GLESGPUPipelineState : public GFXDeviceObject { + GLESGPUPipelineState() = default; + ~GLESGPUPipelineState() override; + + struct DescriptorIndex { + union { + uint32_t binding; + uint32_t unit; + }; + }; + + RasterizerState rs; + DepthStencilState dss; + BlendState bs; + DynamicStateList dynamicStates; + uint32_t subpassIndex = 0; + + PrimitiveMode primitive = PrimitiveMode::TRIANGLE_LIST; + GLenum glPrimitive = GL_TRIANGLES; + IntrusivePtr gpuShader; + IntrusivePtr gpuRenderPass; + IntrusivePtr gpuPipelineLayout; + + uint32_t inputHash = 0; + // bind states + std::vector attributes; + std::vector descriptorIndices; // binding or location + std::vector descriptorOffsets; // set offset to descriptors [set, offset] +}; + +struct GLESGPUGeneralBarrier { + AccessFlags prevAccesses = AccessFlagBit::NONE; + AccessFlags nextAccesses = AccessFlagBit::NONE; + + GLbitfield glBarriers = 0U; + GLbitfield glBarriersByRegion = 0U; +}; + +struct GLESGPUProgramBinary : public GFXDeviceObject { + ccstd::string name; + ccstd::hash_t hash = 0; + GLenum format; + std::vector data; +}; + +struct GLESGPUFence : public GFXDeviceObject { + GLsync sync = nullptr; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.cpp new file mode 100644 index 00000000000..1f595a441f6 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.cpp @@ -0,0 +1,21 @@ +#include "GLESGeneralBarrier.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +GLESGeneralBarrier::GLESGeneralBarrier(const GeneralBarrierInfo &info) : GeneralBarrier(info) { + _typedID = generateObjectID(); + + _gpuBarrier = ccnew GLESGPUGeneralBarrier; + _gpuBarrier->prevAccesses = info.prevAccesses; + _gpuBarrier->nextAccesses = info.nextAccesses; + + glesCreateGeneralBarrier(GLESDevice::getInstance(), _gpuBarrier); +} + +GLESGeneralBarrier::~GLESGeneralBarrier() { + _gpuBarrier = nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.h b/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.h new file mode 100644 index 00000000000..4909835b5d3 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESGeneralBarrier.h @@ -0,0 +1,20 @@ +#pragma once + +#include "gfx-base/states/GFXGeneralBarrier.h" +#include "gfx-gles-common/common/GLESBase.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESGeneralBarrier : public GeneralBarrier { +public: + explicit GLESGeneralBarrier(const GeneralBarrierInfo &info); + ~GLESGeneralBarrier() override; + + inline const GLESGPUGeneralBarrier *gpuBarrier() const { return _gpuBarrier; } + +protected: + GLESGPUGeneralBarrier *_gpuBarrier = nullptr; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.cpp new file mode 100644 index 00000000000..31fd7bfdcd0 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.cpp @@ -0,0 +1,38 @@ +#include "GLESInputAssembler.h" +#include "GLESBuffer.h" +#include "GLESCommands.h" +#include "GLESDevice.h" + +namespace cc::gfx { + +GLESInputAssembler::GLESInputAssembler() { + _typedID = generateObjectID(); +} + +GLESInputAssembler::~GLESInputAssembler() { + destroy(); +} + +void GLESInputAssembler::doInit(const InputAssemblerInfo &info) { + _gpuIA = ccnew GLESGPUInputAssembler; + _gpuIA->attributes = _attributes; + _gpuIA->gpuVertexBuffers.resize(_vertexBuffers.size()); + for (size_t i = 0; i < _gpuIA->gpuVertexBuffers.size(); ++i) { + auto *vb = static_cast(_vertexBuffers[i]); + _gpuIA->gpuVertexBuffers[i] = vb->gpuBufferView(); + } + if (info.indexBuffer) { + _gpuIA->gpuIndexBuffer = static_cast(info.indexBuffer)->gpuBufferView(); + } + + if (info.indirectBuffer) { + _gpuIA->gpuIndirectBuffer = static_cast(info.indirectBuffer)->gpuBufferView(); + } + glesCreateInputAssembler(GLESDevice::getInstance(), _gpuIA); +} + +void GLESInputAssembler::doDestroy() { + _gpuIA = nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.h b/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.h new file mode 100644 index 00000000000..58fbf6d8fed --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESInputAssembler.h @@ -0,0 +1,22 @@ +#pragma once + +#include "gfx-base/GFXInputAssembler.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESInputAssembler final : public InputAssembler { +public: + GLESInputAssembler(); + ~GLESInputAssembler() override; + + GLESGPUInputAssembler *gpuInputAssembler() { return _gpuIA; } + +protected: + void doInit(const InputAssemblerInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuIA; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.cpp new file mode 100644 index 00000000000..755ca0dfe25 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.cpp @@ -0,0 +1,191 @@ + +#include "GLESPipelineCache.h" + +#include +#include + +#include "base/Log.h" +#include "base/BinaryArchive.h" +#include "gfx-base/GFXUtil.h" +#include "GLESGPUObjects.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +//#define PIPELINE_CACHE_FORCE_INCREMENTAL + +#if defined(_WIN32) && !defined(PIPELINE_CACHE_FORCE_INCREMENTAL) + #define PIPELINE_CACHE_FULL +#else + #define PIPELINE_CACHE_INCREMENTAL +#endif + +namespace { +const char *fileName = "/pipeline_cache_gles3.bin"; +const uint32_t MAGIC = 0x4343474C; // "CCGL" +const uint32_t VERSION = 1; + +void saveHeader(BinaryOutputArchive &archive) { + archive.save(MAGIC); + archive.save(VERSION); +} + +void saveItem(BinaryOutputArchive &archive, GLESGPUProgramBinary *binary) { + archive.save(binary->format); + archive.save(static_cast(binary->name.size())); + archive.save(static_cast(binary->data.size())); + archive.save(binary->hash); + archive.save(binary->name.data(), static_cast(binary->name.size())); + archive.save(binary->data.data(), static_cast(binary->data.size())); + CC_LOG_INFO("Save program cache success, name %s.", binary->name.c_str()); +} + +} // namespace + +GLESPipelineCache::GLESPipelineCache() { + _savePath = getPipelineCacheFolder() + fileName; +} + +GLESPipelineCache::~GLESPipelineCache() { // NOLINT +#ifdef PIPELINE_CACHE_FULL + saveCacheFull(); +#endif +} + +bool GLESPipelineCache::loadCache() { + std::ifstream stream(_savePath, std::ios::binary); + if (!stream.is_open()) { + CC_LOG_INFO("Load program cache, no cached files."); + return false; + } + + uint32_t magic = 0; + uint32_t version = 0; + + BinaryInputArchive archive(stream); + auto loadResult = archive.load(magic); + loadResult &= archive.load(version); + + if (magic != MAGIC || version < VERSION) { + // false means invalid cache, need to discard the file content. + return false; + } + + uint32_t cachedItemNum = 0; + GLenum format = GL_NONE; + while (loadResult && archive.load(format)) { + ++cachedItemNum; + + // name length + uint32_t nameLength = 0; + loadResult &= archive.load(nameLength); + + // data length + uint32_t dataLength = 0; + loadResult &= archive.load(dataLength); + + // skip length if not valid. + if (!checkProgramFormat(format)) { + archive.move(dataLength + nameLength + sizeof(GLESGPUProgramBinary::hash)); + continue; + } + + auto *binary = ccnew GLESGPUProgramBinary(); + binary->format = format; + binary->name.resize(nameLength, 0); + binary->data.resize(dataLength, 0); + + // hash + loadResult &= archive.load(binary->hash); + + // name + loadResult &= archive.load(binary->name.data(), nameLength); + + // data + loadResult &= archive.load(binary->data.data(), dataLength); + + _programCaches.emplace(binary->name, binary); + } + + // If the number of cached items does not equal the number of loaded items, it may be necessary to update the cache. + _dirty = cachedItemNum != _programCaches.size(); + CC_LOG_INFO("Load program cache success. records %u, loaded %u", cachedItemNum, _programCaches.size()); + return true; +} + +void GLESPipelineCache::saveCacheIncremental(GLESGPUProgramBinary *binary) { + std::ofstream stream(_savePath, std::ios::binary | std::ios::app); + if (!stream.is_open()) { + CC_LOG_INFO("Save program cache failed."); + return; + } + BinaryOutputArchive archive(stream); + saveItem(archive, binary); +} + +void GLESPipelineCache::saveCacheFull() { + if (!_dirty) { + return; + } + std::ofstream stream(_savePath, std::ios::binary); + if (!stream.is_open()) { + CC_LOG_INFO("Save program cache failed."); + return; + } + BinaryOutputArchive archive(stream); + saveHeader(archive); + + for (auto &pair : _programCaches) { + auto &binary = pair.second; + saveItem(archive, binary); + } + _dirty = false; +} + +void GLESPipelineCache::init() { + glesUpdateProgramBinaryFormats(GLESDevice::getInstance(), _programBinaryFormats); + + auto success = loadCache(); + if (!success) { + // discard cache content. + std::ofstream stream(_savePath, std::ios::binary | std::ios::trunc); +#ifdef PIPELINE_CACHE_INCREMENTAL + if (stream.is_open()) { + BinaryOutputArchive archive(stream); + saveHeader(archive); + } +#endif + } +} + +void GLESPipelineCache::addBinary(GLESGPUProgramBinary *binary) { + _programCaches[binary->name] = binary; +#ifdef PIPELINE_CACHE_INCREMENTAL + saveCacheIncremental(binary); +#endif + _dirty = true; +} + +GLESGPUProgramBinary *GLESPipelineCache::fetchBinary(const ccstd::string &key, ccstd::hash_t hash) { + auto iter = _programCaches.find(key); + if (iter == _programCaches.end()) { + return nullptr; + } + + // if hash not match, re-generate program binary. + if (iter->second->hash != hash) { + _programCaches.erase(iter); + return nullptr; + } + + return iter->second; +} + +bool GLESPipelineCache::checkProgramFormat(GLuint format) const { + return std::any_of(_programBinaryFormats.begin(), _programBinaryFormats.end(), [format](const auto &fmt) { + return format == fmt; + }); +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.h b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.h new file mode 100644 index 00000000000..3434f59316b --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineCache.h @@ -0,0 +1,42 @@ +// +// Created by Zach Lee on 2023/7/29. +// + +#pragma once +#pragma once + +#include "base/Ptr.h" +#include "base/RefCounted.h" +#include "base/std/container/string.h" +#include "base/std/container/unordered_map.h" +#include "base/std/container/vector.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc { +class BinaryOutputArchive; +} + +namespace cc::gfx { +class GLESPipelineCache : public RefCounted { +public: + GLESPipelineCache(); + ~GLESPipelineCache() override; + + void init(); + + void addBinary(GLESGPUProgramBinary *binary); + GLESGPUProgramBinary *fetchBinary(const ccstd::string &key, ccstd::hash_t hash); + bool checkProgramFormat(GLuint format) const; + +private: + bool loadCache(); + void saveCacheFull(); + void saveCacheIncremental(GLESGPUProgramBinary *binary); + + ccstd::vector _programBinaryFormats; + ccstd::unordered_map> _programCaches; + ccstd::string _savePath; + bool _dirty = false; +}; + +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.cpp new file mode 100644 index 00000000000..4577e1f705d --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.cpp @@ -0,0 +1,29 @@ +#include "GLESPipelineLayout.h" +#include "GLESDescriptorSetLayout.h" + +namespace cc::gfx { + +GLESPipelineLayout::GLESPipelineLayout() { + _typedID = generateObjectID(); +} + +GLESPipelineLayout::~GLESPipelineLayout() { + destroy(); +} + +void GLESPipelineLayout::doInit(const PipelineLayoutInfo & /*info*/) { + _gpuPipelineLayout = ccnew GLESGPUPipelineLayout; + _gpuPipelineLayout->setLayouts.reserve(_setLayouts.size()); + for (auto &layout : _setLayouts) { + auto *setLayout = static_cast(layout)->gpuDescriptorSetLayout(); + _gpuPipelineLayout->setLayouts.emplace_back(setLayout); + _gpuPipelineLayout->descriptorCount += setLayout->descriptorCount; + ccstd::hash_combine(_gpuPipelineLayout->hash, setLayout->hash); + } +} + +void GLESPipelineLayout::doDestroy() { + _gpuPipelineLayout = nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.h b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.h new file mode 100644 index 00000000000..d7d73019a30 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineLayout.h @@ -0,0 +1,22 @@ +#pragma once + +#include "gfx-base/GFXPipelineLayout.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESPipelineLayout final : public PipelineLayout { +public: + GLESPipelineLayout(); + ~GLESPipelineLayout() override; + + GLESGPUPipelineLayout *gpuPipelineLayout() const { return _gpuPipelineLayout.get(); } + +protected: + void doInit(const PipelineLayoutInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuPipelineLayout; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.cpp new file mode 100644 index 00000000000..9161a9c1e66 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.cpp @@ -0,0 +1,101 @@ +#include "GLESPipelineState.h" +#include "GLESRenderPass.h" +#include "GLESPipelineLayout.h" +#include "GLESShader.h" +#include "GLESDevice.h" + +namespace cc::gfx { +namespace { +// return ture if shader source is updated. +void updateGPUShaderSourceByRenderPass(GLESGPUShader *gpuShader, GLESGPURenderPass *renderPass, uint32_t subpassIndex) { + CC_ASSERT(subpassIndex < renderPass->subpasses.size()); + if (renderPass->subpasses[subpassIndex].inputs.empty()) { + return; + } + + auto iter = std::find_if(gpuShader->stages.begin(), gpuShader->stages.end(), [](const GLESGPUShader::Stage &stage) { + return stage.type == ShaderStageFlagBit::FRAGMENT; + }); + if (iter == gpuShader->stages.end()) { + return; + } + auto &drawBuffers = renderPass->drawBuffers.at(subpassIndex); + ccstd::string::size_type offset = 0; + for (uint32_t i = 0; i < drawBuffers.size(); ++i) { + const char* layoutPrefix = "layout(location = "; + + std::stringstream ss1; + ss1 << layoutPrefix << i << ") out"; + + std::stringstream ss2; + ss2 << layoutPrefix << i << ") inout"; + + auto &source = iter->source; + auto sIter = source.find(ss1.str(), offset); + if (sIter == std::string::npos) { + sIter = source.find(ss2.str(), offset); + } + + if (sIter != std::string::npos) { + auto loc = sIter + strlen(layoutPrefix); + source[loc] = static_cast('0' + drawBuffers[i]); + offset = loc; + } + } +} + +void initProgram(GLESDevice *device, GLESGPUPipelineState *gpuPipelineState) { + updateGPUShaderSourceByRenderPass(gpuPipelineState->gpuShader, gpuPipelineState->gpuRenderPass, gpuPipelineState->subpassIndex); + glesCreateShaderByBinary(device, gpuPipelineState->gpuShader, gpuPipelineState->gpuPipelineLayout->hash); + if (gpuPipelineState->gpuShader->glProgram == 0) { + glesCreateShaderBySource(device, gpuPipelineState->gpuShader, gpuPipelineState->gpuPipelineLayout->hash); + } + + CC_ASSERT(gpuPipelineState->gpuShader->glProgram); + + // Clear shader source after they're uploaded to GPU + for (auto &stage : gpuPipelineState->gpuShader->stages) { + stage.source.clear(); + stage.source.shrink_to_fit(); + } +} +} // namespace + +GLESPipelineState::GLESPipelineState() { + _typedID = generateObjectID(); +} + +GLESPipelineState::~GLESPipelineState() { + destroy(); +} + +void GLESPipelineState::doInit(const PipelineStateInfo & /*info*/) { + _gpuPipelineState = ccnew GLESGPUPipelineState; + _gpuPipelineState->rs = _rasterizerState; + _gpuPipelineState->dss = _depthStencilState; + _gpuPipelineState->bs = _blendState; + _gpuPipelineState->subpassIndex = _subpass; + _gpuPipelineState->gpuPipelineLayout = static_cast(_pipelineLayout)->gpuPipelineLayout(); + _gpuPipelineState->gpuShader = static_cast(_shader)->gpuShader(); + if (_renderPass) _gpuPipelineState->gpuRenderPass = static_cast(_renderPass)->gpuRenderPass(); + + for (uint32_t i = 0; i < 31; i++) { + if (static_cast(_dynamicStates) & (1 << i)) { + _gpuPipelineState->dynamicStates.push_back(static_cast(1 << i)); + } + } + + auto *device = GLESDevice::getInstance(); + initProgram(device, _gpuPipelineState); + glesCreatePipelineState(device, _gpuPipelineState); +} + +void GLESPipelineState::doDestroy() { + _gpuPipelineState = nullptr; +} + +GLESGPUPipelineState::~GLESGPUPipelineState() { + glesDestroyPipelineState(GLESDevice::getInstance(), this); +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.h b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.h new file mode 100644 index 00000000000..e7ba8ce8e78 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESPipelineState.h @@ -0,0 +1,23 @@ +#pragma once + +#include "gfx-base/GFXPipelineState.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESPipelineState final : public PipelineState { +public: + GLESPipelineState(); + ~GLESPipelineState() override; + + GLESGPUPipelineState *gpuPipelineState() const { return _gpuPipelineState.get(); } + +protected: + void doInit(const PipelineStateInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuPipelineState; +}; + + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp index 6c052fae596..ccc989321fb 100644 --- a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp +++ b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.cpp @@ -1,14 +1,29 @@ #include "GLESQueue.h" +#include "gfx-gles-common/egl/Context.h" +#include "gfx-gles-common/common/GLESCommandBuffer.h" namespace cc::gfx { +GLESQueue::~GLESQueue() { + destroy(); +} -bool GLESQueue::hasComplete(TaskHandle taskId) { - return _lastTaskId.load() >= taskId; +void GLESQueue::startThread() { + _isAsyncQueue = true; + _thread = std::thread(&GLESQueue::threadMain, this); } -void GLESQueue::wait(TaskHandle taskId) { - std::unique_lock lock(_mutex); - _taskCv.wait(lock, [=]() {return hasComplete(taskId); }); +void GLESQueue::initContext(egl::Context *context) { + _eglContext = context; + queueTask([this]() { + _eglContext->makeCurrent(); + }); +} + +void GLESQueue::surfaceDestroy(egl::Surface *surface) { + IntrusivePtr const tmpSurface(surface); // hold reference + queueTask([=]() { + _eglContext->makeCurrent(); + }); } void GLESQueue::waitIdle() { @@ -16,6 +31,17 @@ void GLESQueue::waitIdle() { wait(task); } +bool GLESQueue::hasComplete(TaskHandle taskId) { + return !_isAsyncQueue || _lastTaskId.load() >= taskId; +} + +void GLESQueue::wait(TaskHandle taskId) { + if (_isAsyncQueue) { + std::unique_lock lock(_mutex); + _taskCv.wait(lock, [=]() { return hasComplete(taskId); }); + } +} + void GLESQueue::threadMain() { while (!_exit.load()) { if (!runTask()) { @@ -53,4 +79,32 @@ bool GLESQueue::hasTask() { return !_taskQueue.empty(); } -} // namespace cc::gfx \ No newline at end of file +void GLESQueue::submit(CommandBuffer *const *cmdBuffs, uint32_t count) { + for (uint32_t i = 0; i < count; ++i) { + auto *commandBuffer = static_cast(cmdBuffs[i]); + commandBuffer->attachContext(_eglContext); + commandBuffer->setTaskHandle( + queueTask([=]() { + glFlush(); + commandBuffer->executeCommands(); + }) + ); + } +} + +void GLESQueue::doInit(const QueueInfo &info) { + std::ignore = info; +} + +void GLESQueue::doDestroy() { + _exit.store(true); + { + std::lock_guard const lock(_mutex); + _cv.notify_all(); + } + if (_thread.joinable()) { + _thread.join(); + } +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h index b007d4c4b49..ecb2deb5482 100644 --- a/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h +++ b/native/cocos/renderer/gfx-gles-common/common/GLESQueue.h @@ -6,22 +6,44 @@ #include #include #include "base/std/container/vector.h" +#include "gfx-base/GFXQueue.h" namespace cc::gfx { +namespace egl { +class Context; +class Surface; +} // namespace egl -class GLESQueue { +class GLESQueue : public Queue { public: GLESQueue() = default; - virtual ~GLESQueue() = default; + ~GLESQueue() override; using TaskHandle = uint32_t; + void startThread(); + void initContext(egl::Context *context); + void surfaceDestroy(egl::Surface *surface); + bool hasComplete(TaskHandle taskId); void wait(TaskHandle taskId); void waitIdle(); + bool isAsyncQueue() const { return _isAsyncQueue; } + template TaskHandle queueTask(T &&task) { + if (_isAsyncQueue) { + return queueTaskInternal(std::forward(task)); + } + task(); + return _taskCounter; + } +private: + friend class GLESDevice; + + template + TaskHandle queueTaskInternal (T &&task) { TaskHandle res = _taskCounter.fetch_add(1); { std::lock_guard const lock(_taskMutex); @@ -34,14 +56,15 @@ class GLESQueue { return res; } -private: - friend class Device; - struct Task { TaskHandle taskId; std::function func; }; + void submit(CommandBuffer *const *cmdBuffs, uint32_t count) override; + void doInit(const QueueInfo &info) override; + void doDestroy() override; + void threadMain(); bool runTask(); bool hasTask(); @@ -61,6 +84,9 @@ class GLESQueue { std::atomic_bool _exit = false; std::atomic _taskCounter = 0; std::atomic _lastTaskId = 0; + + bool _isAsyncQueue{false}; + egl::Context *_eglContext = nullptr; }; -} // namespace cc::gfx \ No newline at end of file +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.cpp new file mode 100644 index 00000000000..94721046d4a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.cpp @@ -0,0 +1,53 @@ +#include "GLESRecycleBin.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +void GLESRecycleBin::collect(const GLESGPUBuffer *buffer) { + if (buffer->glBuffer != 0) { + _buffers.emplace_back(buffer->glBuffer); + } +} + +void GLESRecycleBin::collect(const GLESGPUTexture *texture) { + if (texture->useRenderBuffer && texture->glRenderbuffer != 0) { + _renderBuffers.emplace_back(texture->glRenderbuffer); + } else if (texture->glTexture != 0) { + _textures.emplace_back(texture->glTexture); + } +} + +void GLESRecycleBin::collect(const GLESGPUShader *shader) { + if (shader->glProgram != 0) { + _programs.emplace_back(shader->glProgram); + } +} + +void GLESRecycleBin::clear() { + auto *device = GLESDevice::getInstance(); + if (!_buffers.empty()) { + glesDestroyBuffer(device, _buffers.data(), static_cast(_buffers.size())); + _buffers.clear(); + } + + if (!_textures.empty()) { + glesDestroyTexture(device, _textures.data(), static_cast(_textures.size())); + _textures.clear(); + } + + if (!_textures.empty()) { + glesDestroyRenderBuffer(device, _renderBuffers.data(), static_cast(_renderBuffers.size())); + _renderBuffers.clear(); + } + + if (!_programs.empty()) { + for (auto &program : _programs) { + glesDestroyProgram(device, program); + } + _programs.clear(); + } +} + + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.h b/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.h new file mode 100644 index 00000000000..bc80603a95a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESRecycleBin.h @@ -0,0 +1,25 @@ +#pragma once + +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESRecycleBin { +public: + GLESRecycleBin() = default; + ~GLESRecycleBin() = default; + + void collect(const GLESGPUBuffer *buffer); + void collect(const GLESGPUTexture *texture); + void collect(const GLESGPUShader *shader); + + void clear(); + +private: + ccstd::vector _buffers; + ccstd::vector _textures; + ccstd::vector _renderBuffers; + ccstd::vector _programs; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.cpp new file mode 100644 index 00000000000..34c6fe2f426 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.cpp @@ -0,0 +1,56 @@ +#include "GLESRenderPass.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +GLESRenderPass::GLESRenderPass() { + _typedID = generateObjectID(); +} + +GLESRenderPass::~GLESRenderPass() { + destroy(); +} + +void GLESRenderPass::doInit(const RenderPassInfo & /*info*/) { + _gpuRenderPass = ccnew GLESGPURenderPass; + _gpuRenderPass->colorAttachments = _colorAttachments; + _gpuRenderPass->depthStencilAttachment = _depthStencilAttachment; + _gpuRenderPass->depthStencilResolveAttachment = _depthStencilResolveAttachment; + _gpuRenderPass->subpasses = _subpasses; + _gpuRenderPass->dependencies = _dependencies; + + // assign a dummy subpass if not specified + auto colorCount = static_cast(_gpuRenderPass->colorAttachments.size()); + if (_gpuRenderPass->subpasses.empty()) { + _gpuRenderPass->subpasses.emplace_back(); + auto &subpass = _gpuRenderPass->subpasses.back(); + subpass.colors.resize(_colorAttachments.size()); + for (uint32_t i = 0U; i < _colorAttachments.size(); ++i) { + subpass.colors[i] = i; + } + if (_depthStencilAttachment.format != Format::UNKNOWN) { + subpass.depthStencil = colorCount; + } + if (_depthStencilResolveAttachment.format != Format::UNKNOWN) { + subpass.depthStencil = colorCount + 1; + } + } else { + // unify depth stencil index + for (auto &subpass : _gpuRenderPass->subpasses) { + if (subpass.depthStencil != INVALID_BINDING && subpass.depthStencil >= colorCount) { + subpass.depthStencil = colorCount; + } + if (subpass.depthStencilResolve != INVALID_BINDING && subpass.depthStencil >= colorCount) { + subpass.depthStencilResolve = colorCount + 1; + } + } + } + glesCreateRenderPass(GLESDevice::getInstance(), _gpuRenderPass); +} + +void GLESRenderPass::doDestroy() { + _gpuRenderPass = nullptr; +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.h b/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.h new file mode 100644 index 00000000000..01b14f53df3 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESRenderPass.h @@ -0,0 +1,21 @@ +#pragma once +#include "gfx-base/GFXRenderPass.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESRenderPass final : public RenderPass { +public: + GLESRenderPass(); + ~GLESRenderPass() override; + + GLESGPURenderPass *gpuRenderPass() const { return _gpuRenderPass.get(); } + +protected: + void doInit(const RenderPassInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuRenderPass; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESSampler.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESSampler.cpp new file mode 100644 index 00000000000..ccca1be057d --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESSampler.cpp @@ -0,0 +1,24 @@ +#include "GLESSampler.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +GLESSampler::GLESSampler(const SamplerInfo& info) : Sampler(info) { + _typedID = generateObjectID(); + + _gpuSampler = ccnew GLESGPUSampler; + _gpuSampler->minFilter = _info.minFilter; + _gpuSampler->magFilter = _info.magFilter; + _gpuSampler->mipFilter = _info.mipFilter; + _gpuSampler->addressU = _info.addressU; + _gpuSampler->addressV = _info.addressV; + _gpuSampler->addressW = _info.addressW; + + glesCreateSampler(GLESDevice::getInstance(), _gpuSampler); +} + +GLESGPUSampler::~GLESGPUSampler() { + glesDestroySampler(GLESDevice::getInstance(), this); +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESSampler.h b/native/cocos/renderer/gfx-gles-common/common/GLESSampler.h new file mode 100644 index 00000000000..072b72f8056 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESSampler.h @@ -0,0 +1,18 @@ +#pragma once + +#include "gfx-base/states/GFXSampler.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESSampler final : public Sampler { +public: + explicit GLESSampler(const SamplerInfo& info); + ~GLESSampler() override = default; + + GLESGPUSampler *gpuSampler() const { return _gpuSampler.get(); } +private: + IntrusivePtr _gpuSampler; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESShader.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESShader.cpp new file mode 100644 index 00000000000..2fbbe087290 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESShader.cpp @@ -0,0 +1,40 @@ +#include "GLESShader.h" +#include "GLESDevice.h" +#include "GLESCommands.h" + +namespace cc::gfx { + +GLESShader::GLESShader() { + _typedID = generateObjectID(); +} + +GLESShader::~GLESShader() { + destroy(); +} + +void GLESShader::doInit(const ShaderInfo & /*info*/) { + _gpuShader = ccnew GLESGPUShader; + _gpuShader->name = _name; + _gpuShader->blocks = _blocks; + _gpuShader->buffers = _buffers; + _gpuShader->samplerTextures = _samplerTextures; + _gpuShader->images = _images; + _gpuShader->hash = _hash; + for (auto &stage : _stages) { + _gpuShader->stages.emplace_back(); + auto &back = _gpuShader->stages.back(); + back.source = std::move(stage.source); + back.type = stage.stage; + back.glShader = 0; + } +} + +void GLESShader::doDestroy() { + _gpuShader = nullptr; +} + +GLESGPUShader::~GLESGPUShader() { + GLESDevice::getInstance()->recycleBin()->collect(this); +} + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESShader.h b/native/cocos/renderer/gfx-gles-common/common/GLESShader.h new file mode 100644 index 00000000000..86905021c16 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESShader.h @@ -0,0 +1,22 @@ +#pragma once + +#include "gfx-base/GFXShader.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESShader final : public Shader { +public: + GLESShader(); + ~GLESShader() override; + + GLESGPUShader *gpuShader() const { return _gpuShader; } + +protected: + void doInit(const ShaderInfo &info) override; + void doDestroy() override; + + IntrusivePtr _gpuShader; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.cpp new file mode 100644 index 00000000000..d08f21e4f02 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.cpp @@ -0,0 +1,189 @@ +#include "GLESSwapchain.h" + +#if CC_SWAPPY_ENABLED + #include "platform/android/AndroidPlatform.h" + #include "swappy/swappyGL.h" +#endif + +#if (CC_PLATFORM == CC_PLATFORM_ANDROID) + #include "android/native_window.h" +#elif CC_PLATFORM == CC_PLATFORM_OHOS + #include + #include +#endif + +#include "application/ApplicationManager.h" +#include "platform/interfaces/modules/IXRInterface.h" +#include "GLESTexture.h" +#include "gfx-gles-common/common/GLESDevice.h" +#include "gfx-gles-common/egl/Surface.h" + +namespace cc::gfx { + +GLESSwapchain::GLESSwapchain() { + _typedID = generateObjectID(); +} + +GLESSwapchain::~GLESSwapchain() { + destroy(); +} + +void GLESSwapchain::doInit(const SwapchainInfo &info) { + _xr = CC_GET_XR_INTERFACE(); + if (_xr) { + _xr->updateXRSwapchainTypedID(getTypedID()); + } + auto width = static_cast(info.width); + auto height = static_cast(info.height); + const auto *context = GLESDevice::getInstance()->getMainContext(); + _gpuSwapchain = ccnew GLESGPUSwapchain; +#if CC_PLATFORM == CC_PLATFORM_LINUX + auto window = reinterpret_cast(info.windowHandle); +#else + auto *window = reinterpret_cast(info.windowHandle); +#endif + +#if CC_PLATFORM == CC_PLATFORM_ANDROID || CC_PLATFORM == CC_PLATFORM_OHOS + EGLint nFmt = 0; + if (eglGetConfigAttrib(context->getDisplay(), context->getConfig(), EGL_NATIVE_VISUAL_ID, &nFmt) == EGL_FALSE) { + CC_LOG_ERROR("Getting configuration attributes failed."); + return; + } + + #if CC_SWAPPY_ENABLED + bool enableSwappy = true; + auto *platform = static_cast(cc::BasePlatform::getPlatform()); + enableSwappy &= SwappyGL_init(static_cast(platform->getEnv()), static_cast(platform->getActivity())); + int32_t fps = cc::BasePlatform::getPlatform()->getFps(); + if (enableSwappy) { + if (!fps) + SwappyGL_setSwapIntervalNS(SWAPPY_SWAP_60FPS); + else + SwappyGL_setSwapIntervalNS(1000000000L / fps); //ns + enableSwappy &= SwappyGL_setWindow(window); + _gpuSwapchain->swappyEnabled = enableSwappy; + } else { + CC_LOG_ERROR("Failed to enable Swappy in current GL swapchain, fallback instead."); + } + + #endif + + if (_xr) { + width = _xr->getXRConfig(xr::XRConfigKey::SWAPCHAIN_WIDTH).getInt(); + height = _xr->getXRConfig(xr::XRConfigKey::SWAPCHAIN_HEIGHT).getInt(); + } + + #if CC_PLATFORM == CC_PLATFORM_ANDROID + ANativeWindow_setBuffersGeometry(window, width, height, nFmt); + #elif CC_PLATFORM == CC_PLATFORM_OHOS + NativeLayerHandle(window, NativeLayerOps::SET_WIDTH_AND_HEIGHT, width, height); + NativeLayerHandle(window, NativeLayerOps::SET_FORMAT, nFmt); + #endif +#endif + + auto surfaceType = _xr ? _xr->acquireEGLSurfaceType(getTypedID()) : EGLSurfaceType::WINDOW; + if (surfaceType == EGLSurfaceType::WINDOW) { + auto *surface = ccnew egl::WindowSurface(); + if (!surface->init(context->getConfig(), window)) { + CC_LOG_ERROR("Create window surface failed."); + return; + } + _gpuSwapchain->surface = surface; + } else { + _gpuSwapchain->surface = context->getPBufferSurface(); + } + + switch (_vsyncMode) { + case VsyncMode::OFF: _gpuSwapchain->eglSwapInterval = 0; break; + case VsyncMode::ON: + case VsyncMode::RELAXED: _gpuSwapchain->eglSwapInterval = 1; break; + case VsyncMode::MAILBOX: _gpuSwapchain->eglSwapInterval = 0; break; + case VsyncMode::HALF: _gpuSwapchain->eglSwapInterval = 2; break; + default: break; + } + + ///////////////////// Texture Creation ///////////////////// + + _colorTexture = ccnew GLESTexture; + _depthStencilTexture = ccnew GLESTexture; + + SwapchainTextureInfo textureInfo; + textureInfo.swapchain = this; + textureInfo.format = Format::RGBA8; + textureInfo.width = width; + textureInfo.height = height; + initTexture(textureInfo, _colorTexture); + + textureInfo.format = Format::DEPTH_STENCIL; + initTexture(textureInfo, _depthStencilTexture); + + _gpuSwapchain->gpuColorTexture = static_cast(_colorTexture.get())->gpuTexture(); +} + +void GLESSwapchain::doDestroy() { + _depthStencilTexture = nullptr; + _colorTexture = nullptr; + doDestroySurface(); + _gpuSwapchain = nullptr; +} + +void GLESSwapchain::doResize(uint32_t width, uint32_t height, SurfaceTransform /*transform*/) { + _colorTexture->resize(width, height); + _depthStencilTexture->resize(width, height); + + if (_windowHandle) { + doCreateSurface(_windowHandle); + } +} + +void GLESSwapchain::doDestroySurface() { + auto *queue = GLESDevice::getInstance()->getQueue(QueueType::GRAPHICS); + queue->surfaceDestroy(_gpuSwapchain->surface); + queue->waitIdle(); + _gpuSwapchain->surface = nullptr; +} + +void GLESSwapchain::doCreateSurface(void *windowHandle) { +#if CC_PLATFORM == CC_PLATFORM_LINUX + auto window = reinterpret_cast(windowHandle); +#else + auto *window = reinterpret_cast(windowHandle); +#endif + auto *context = GLESDevice::getInstance()->getMainContext(); + + EGLint nFmt = 0; + if (eglGetConfigAttrib(context->getDisplay(), context->getConfig(), EGL_NATIVE_VISUAL_ID, &nFmt) == EGL_FALSE) { + CC_LOG_ERROR("Getting configuration attributes failed."); + return; + } + + auto width = static_cast(_colorTexture->getWidth()); + auto height = static_cast(_colorTexture->getHeight()); + CC_UNUSED_PARAM(width); + CC_UNUSED_PARAM(height); + +#if CC_SWAPPY_ENABLED + if (_gpuSwapchain->swappyEnabled) { + _gpuSwapchain->swappyEnabled &= SwappyGL_setWindow(window); + } +#endif + +#if CC_PLATFORM == CC_PLATFORM_ANDROID + ANativeWindow_setBuffersGeometry(window, width, height, nFmt); +#elif CC_PLATFORM == CC_PLATFORM_OHOS + NativeLayerHandle(window, NativeLayerOps::SET_WIDTH_AND_HEIGHT, width, height); + NativeLayerHandle(window, SET_FORMAT, nFmt); +#endif + + auto surfaceType = _xr ? _xr->acquireEGLSurfaceType(getTypedID()) : EGLSurfaceType::WINDOW; + if (surfaceType == EGLSurfaceType::WINDOW) { + auto *surface = ccnew egl::WindowSurface(); + if (!surface->init(context->getConfig(), window)) { + CC_LOG_ERROR("Recreate window surface failed."); + } + _gpuSwapchain->surface = surface; + } else { + _gpuSwapchain->surface = context->getPBufferSurface(); + } +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.h b/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.h new file mode 100644 index 00000000000..f3e24c0e82c --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESSwapchain.h @@ -0,0 +1,30 @@ +#pragma once + +#include "gfx-base/GFXSwapchain.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc { +class IXRInterface; +} // namespace cc + +namespace cc::gfx { + +class GLESSwapchain final : public Swapchain { +public: + GLESSwapchain(); + ~GLESSwapchain() override; + + GLESGPUSwapchain *gpuSwapchain() const { return _gpuSwapchain.get(); } + +protected: + void doInit(const SwapchainInfo &info) override; + void doDestroy() override; + void doResize(uint32_t width, uint32_t height, SurfaceTransform transform) override; + void doDestroySurface() override; + void doCreateSurface(void *windowHandle) override; + + IntrusivePtr _gpuSwapchain; + IXRInterface *_xr{nullptr}; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESTexture.cpp b/native/cocos/renderer/gfx-gles-common/common/GLESTexture.cpp new file mode 100644 index 00000000000..07c16b5e13c --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESTexture.cpp @@ -0,0 +1,150 @@ +#include "GLESTexture.h" +#include "GLESSwapchain.h" +#include "GLESCommands.h" +#include "GLESDevice.h" + +namespace cc::gfx { + +GLESTexture::GLESTexture() { + _typedID = generateObjectID(); +} + +GLESTexture::~GLESTexture() { + destroy(); +} + +void GLESTexture::doInit(const TextureInfo & /*info*/) { + _gpuTexture = ccnew GLESGPUTexture; + _gpuTexture->type = _info.type; + _gpuTexture->format = _info.format; + _gpuTexture->usage = _info.usage; + _gpuTexture->width = _info.width; + _gpuTexture->height = _info.height; + _gpuTexture->depth = _info.depth; + _gpuTexture->arrayLayer = _info.layerCount; + _gpuTexture->mipLevel = _info.levelCount; + _gpuTexture->glSamples = static_cast(_info.samples); + _gpuTexture->flags = _info.flags; + _gpuTexture->size = _size; + _gpuTexture->isPowerOf2 = math::isPowerOfTwo(_info.width) && math::isPowerOfTwo(_info.height); + + if (_info.externalRes != nullptr) { + // compatibility + if (!hasAnyFlags(_gpuTexture->flags, TextureFlagBit::EXTERNAL_OES | TextureFlagBit::EXTERNAL_NORMAL)) { + _gpuTexture->flags |= TextureFlagBit::EXTERNAL_OES; + } + _gpuTexture->glTexture = static_cast(reinterpret_cast(_info.externalRes)); + } + + glesCreateTexture(GLESDevice::getInstance(), _gpuTexture); + + createTextureView(); +} + +void GLESTexture::doInit(const TextureViewInfo & /*info*/) { + _gpuTexture = static_cast(_viewInfo.texture)->gpuTexture(); + CC_ASSERT(_viewInfo.texture->getFormat() == _viewInfo.format); + + createTextureView(); +} + +void GLESTexture::doInit(const SwapchainTextureInfo & /*info*/) { + _gpuTexture = ccnew GLESGPUTexture; + _gpuTexture->type = _info.type; + _gpuTexture->format = _info.format; + _gpuTexture->usage = _info.usage; + _gpuTexture->width = _info.width; + _gpuTexture->height = _info.height; + _gpuTexture->depth = _info.depth; + _gpuTexture->arrayLayer = _info.layerCount; + _gpuTexture->mipLevel = _info.levelCount; + _gpuTexture->glSamples = static_cast(_info.samples); + _gpuTexture->flags = _info.flags; + _gpuTexture->size = _size; + _gpuTexture->memoryAllocated = false; + _gpuTexture->swapchain = static_cast(_swapchain)->gpuSwapchain(); + + createTextureView(); +} + +void GLESTexture::createTextureView() { + _gpuTextureView = ccnew GLESGPUTextureView; + _gpuTextureView->texture = _gpuTexture; + _gpuTextureView->type = _viewInfo.type; + _gpuTextureView->format = _viewInfo.format; + _gpuTextureView->baseLevel = _viewInfo.baseLevel; + _gpuTextureView->levelCount = _viewInfo.levelCount; + _gpuTextureView->baseLayer = _viewInfo.baseLayer; + _gpuTextureView->layerCount = _viewInfo.layerCount; +} + +void GLESTexture::doDestroy() { + _gpuTexture = nullptr; + _gpuTextureView = nullptr; +} + +void GLESTexture::doResize(uint32_t width, uint32_t height, uint32_t size) { + if (!_gpuTexture->memoryAllocated || + hasFlag(_gpuTexture->flags, TextureFlagBit::EXTERNAL_OES) || + hasFlag(_gpuTexture->flags, TextureFlagBit::EXTERNAL_NORMAL)) { + return; + } + + if (!_gpuTexture->immutable) { + _gpuTexture->width = width; + _gpuTexture->height = height; + _gpuTexture->size = size; + _gpuTexture->isPowerOf2 = math::isPowerOfTwo(_info.width) && math::isPowerOfTwo(_info.height);; + _gpuTexture->mipLevel = _info.levelCount; + + _gpuTextureView->levelCount = _info.levelCount; + glesResizeTexture(GLESDevice::getInstance(), _gpuTexture); + return; + } + auto *gpuTexture = ccnew GLESGPUTexture; + gpuTexture->width = width; + gpuTexture->height = height; + gpuTexture->size = size; + gpuTexture->isPowerOf2 = math::isPowerOfTwo(_info.width) && math::isPowerOfTwo(_info.height);; + gpuTexture->mipLevel = _info.levelCount; + + gpuTexture->depth = _gpuTexture->depth; + gpuTexture->type = _gpuTexture->type; + gpuTexture->format = _gpuTexture->format; + gpuTexture->usage = _gpuTexture->usage; + gpuTexture->flags = _gpuTexture->flags; + + gpuTexture->arrayLayer = _gpuTexture->arrayLayer; + gpuTexture->mipLevel = _gpuTexture->mipLevel; + + gpuTexture->immutable = _gpuTexture->immutable; + gpuTexture->useRenderBuffer = _gpuTexture->useRenderBuffer; + gpuTexture->memoryAllocated = _gpuTexture->memoryAllocated; + + gpuTexture->glInternalFmt = _gpuTexture->glInternalFmt ; + gpuTexture->glFormat = _gpuTexture->glFormat; + gpuTexture->glType = _gpuTexture->glType; + gpuTexture->glUsage = _gpuTexture->glUsage; + gpuTexture->glSamples = _gpuTexture->glSamples; + gpuTexture->glTexture = _gpuTexture->glTexture; + gpuTexture->glRenderbuffer = _gpuTexture->glRenderbuffer; + + gpuTexture->glWrapS = _gpuTexture->glWrapS; + gpuTexture->glWrapT = _gpuTexture->glWrapT; + gpuTexture->glMinFilter = _gpuTexture->glMinFilter; + gpuTexture->glMagFilter = _gpuTexture->glMagFilter; + gpuTexture->swapchain = _gpuTexture->swapchain; + _gpuTexture = gpuTexture; + glesCreateTexture(GLESDevice::getInstance(), _gpuTexture); + + createTextureView(); +} + +GLESGPUTexture::~GLESGPUTexture() { + if (hasFlag(flags, TextureFlagBit::EXTERNAL_OES) || + hasFlag(flags, TextureFlagBit::EXTERNAL_NORMAL)) { + return; + } + GLESDevice::getInstance()->recycleBin()->collect(this); +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/common/GLESTexture.h b/native/cocos/renderer/gfx-gles-common/common/GLESTexture.h new file mode 100644 index 00000000000..b4544fef81d --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/common/GLESTexture.h @@ -0,0 +1,29 @@ +#pragma once + +#include "gfx-base/GFXTexture.h" +#include "gfx-gles-common/common/GLESGPUObjects.h" + +namespace cc::gfx { + +class GLESTexture final : public gfx::Texture { +public: + GLESTexture(); + ~GLESTexture() override; + + GLESGPUTexture *gpuTexture() const { return _gpuTexture.get(); } + GLESGPUTextureView *gpuTextureView() const { return _gpuTextureView.get(); } + +private: + void doInit(const TextureInfo &info) override; + void doInit(const TextureViewInfo &info) override; + void doInit(const SwapchainTextureInfo &info) override; + void doDestroy() override; + void doResize(uint32_t width, uint32_t height, uint32_t size) override; + + void createTextureView(); + + IntrusivePtr _gpuTexture; + IntrusivePtr _gpuTextureView; +}; + +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/egl/Base.h b/native/cocos/renderer/gfx-gles-common/egl/Base.h index c0f91c05994..d38abc2f9d4 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Base.h +++ b/native/cocos/renderer/gfx-gles-common/egl/Base.h @@ -1,24 +1,6 @@ #pragma once -#include "base/Log.h" - #include "gfx-gles-common/loader/eglw.h" -#include "gfx-gles-common/loader/gles2w.h" -#include "gfx-gles-common/loader/gles3w.h" - -#if CC_DEBUG > 0 - #define EGL_CHECK(x) \ - do { \ - x; \ - const EGLint err = eglGetError(); \ - if (err != EGL_SUCCESS) { \ - CC_LOG_ERROR("%s returned EGL error: 0x%x", #x, err); \ - CC_ABORT(); \ - } \ - } while (0) -#else - #define EGL_CHECK(x) x -#endif namespace cc::gfx::egl { diff --git a/native/cocos/renderer/gfx-gles-common/egl/Context.cpp b/native/cocos/renderer/gfx-gles-common/egl/Context.cpp index b41d363c197..ce7a6018524 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Context.cpp +++ b/native/cocos/renderer/gfx-gles-common/egl/Context.cpp @@ -1,4 +1,6 @@ #include "Context.h" + +#include "gfx-gles-common/egl/Debug.h" #include "gfx-gles-common/egl/Instance.h" namespace cc::gfx::egl { @@ -83,6 +85,7 @@ EGLConfig chooseConfig(EGLDisplay eglDisplay, const Config &cfg, bool qualityPre lastScore = currScore; } } + CC_LOG_INFO("Setup EGLConfig: depth [%d] stencil [%d] sampleBuffer [%d] sampleCount [%d]", depth, stencil, sampleBuffers, sampleCount); return eglConfig; } } // namespace @@ -97,35 +100,35 @@ Context::~Context() { bool Context::createEGLContext(const ContextInfo &info) { auto *instance = Instance::getInstance(); - + EGL_CHECK(_display = eglGetDisplay(EGL_DEFAULT_DISPLAY)); _config = chooseConfig(_display, info.config, info.qualityPreferred, info.msaaEnabled); - _majorVersion = info.majorVersion; - _minorVersion = _majorVersion >= 3 ? 2 : 0; + _glMajorVersion = info.majorVersion; + _glMinorVersion = _glMajorVersion >= 3 ? 2 : 0; ccstd::vector eglAttributes; if (instance->checkExtension(CC_TOSTR(EGL_KHR_create_context))) { eglAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); - eglAttributes.push_back(_majorVersion); + eglAttributes.push_back(_glMajorVersion); eglAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); - eglAttributes.push_back(_minorVersion); + eglAttributes.push_back(_glMinorVersion); #if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION eglAttributes.push_back(EGL_CONTEXT_FLAGS_KHR); eglAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR); #endif eglAttributes.push_back(EGL_NONE); - for (EGLint m = _minorVersion; m >= 0; --m) { + for (EGLint m = _glMinorVersion; m >= 0; --m) { eglAttributes[3] = m; _context = eglCreateContext(_display, _config, info.sharedContext, eglAttributes.data()); auto err = eglGetError(); // QNX throws egl errors on mismatch if (_context && err == EGL_SUCCESS) { - _minorVersion = m; + _glMinorVersion = m; break; } } } else { eglAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); - eglAttributes.push_back(_majorVersion); + eglAttributes.push_back(_glMajorVersion); eglAttributes.push_back(EGL_NONE); EGL_CHECK(_context = eglCreateContext(_display, _config, info.sharedContext, eglAttributes.data())); } @@ -150,8 +153,6 @@ bool Context::init(const ContextInfo &info) { if (!createPBuffer()) { return false; } - - makeCurrent(); return true; } diff --git a/native/cocos/renderer/gfx-gles-common/egl/Context.h b/native/cocos/renderer/gfx-gles-common/egl/Context.h index 1bf38de5096..5cdfa311eee 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Context.h +++ b/native/cocos/renderer/gfx-gles-common/egl/Context.h @@ -1,10 +1,10 @@ #pragma once -#include "base/std/container/vector.h" +#include #include "base/std/container/string.h" -#include "gfx-gles-common/egl/Surface.h" +#include "base/std/container/vector.h" #include "gfx-gles-common/egl/Base.h" -#include +#include "gfx-gles-common/egl/Surface.h" namespace cc::gfx::egl { @@ -19,7 +19,7 @@ struct ContextInfo { class Context { public: - Context() = default; + explicit Context(uint32_t index) : _contextID(index) {} ~Context(); bool init(const ContextInfo &info); @@ -30,27 +30,31 @@ class Context { void surfaceDestroy(EGLSurface surface); void resetCurrent(bool noContext = false); + PBufferSurface *getPBufferSurface() const { return _pBuffer.get(); } + EGLDisplay getDisplay() const { return _display; } EGLContext getContext() const { return _context; } EGLConfig getConfig() const { return _config; } EGLSurface getCurrentDrawSurface() const { return _currentDrawSurface; } EGLSurface getCurrentReadSurface() const { return _currentReadSurface; } - uint32_t getMinorVersion() const { return _glMinorVersion; } - uint32_t getMajorVersion() const { return _glMajorVersion; } + EGLint getMinorVersion() const { return _glMinorVersion; } + EGLint getMajorVersion() const { return _glMajorVersion; } + + uint32_t getContextID() const { return _contextID; } private: bool createEGLContext(const ContextInfo &info); bool createPBuffer(); + uint32_t _contextID = 0; + EGLContext _context = EGL_NO_CONTEXT; EGLDisplay _display = EGL_NO_DISPLAY; EGLSurface _currentDrawSurface = EGL_NO_SURFACE; EGLSurface _currentReadSurface = EGL_NO_SURFACE; EGLConfig _config = EGL_NO_CONFIG_KHR; - uint32_t _glMajorVersion{0U}; - uint32_t _glMinorVersion{0U}; - EGLint _majorVersion{0}; - EGLint _minorVersion{0}; + EGLint _glMajorVersion{0U}; + EGLint _glMinorVersion{0U}; ccstd::vector _extensions; std::unique_ptr _pBuffer; }; diff --git a/native/cocos/renderer/gfx-gles-common/egl/Debug.h b/native/cocos/renderer/gfx-gles-common/egl/Debug.h new file mode 100644 index 00000000000..1154b033068 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/egl/Debug.h @@ -0,0 +1,31 @@ +#pragma once + +#include "base/Log.h" + +#if CC_DEBUG > 0 + #define EGL_CHECK(x) \ + do { \ + x; \ + const EGLint err = eglGetError(); \ + if (err != EGL_SUCCESS) { \ + CC_LOG_ERROR("%s returned EGL error: 0x%x", #x, err); \ + CC_ABORT(); \ + } \ + } while (0) +#else + #define EGL_CHECK(x) x +#endif + +#if CC_DEBUG > 0 + #define GL_CHECK(x) \ + do { \ + x; \ + const GLenum err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + CC_LOG_ERROR("%s returned GL error: 0x%x", #x, err); \ + CC_ABORT(); \ + } \ + } while (0) +#else + #define GL_CHECK(x) x +#endif \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp b/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp index 87fc846996d..addf2ab510c 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp +++ b/native/cocos/renderer/gfx-gles-common/egl/Instance.cpp @@ -5,9 +5,12 @@ #include "base/Log.h" #include "base/StringUtil.h" #include "gfx-gles-common/egl/Base.h" +#include "gfx-gles-common/egl/Debug.h" #include "gfx-gles-common/loader/eglw.h" #include "gfx-gles-common/loader/gles2w.h" +#ifdef CC_USE_GLES3 #include "gfx-gles-common/loader/gles3w.h" +#endif namespace cc::gfx::egl { namespace { @@ -17,10 +20,10 @@ std::unique_ptr gInstance; } void *getProcAddress(const char *proc) { - if (eglGetProcAddress) { - return reinterpret_cast(eglGetProcAddress(proc)); - } - return gLibEGL->getProcAddress(proc); + void *res = nullptr; + if (eglGetProcAddress) res = reinterpret_cast(eglGetProcAddress(proc)); + if (res == nullptr) res = reinterpret_cast(gLibEGL->getProcAddress(proc)); + return res; } namespace { @@ -86,13 +89,14 @@ bool loadLibrary() { return false; } } + gLibEGL = std::move(libEGL); + gLibGLES = std::move(libGLES); eglwLoadProcs(getProcAddress); gles2wLoadProcs(getProcAddress); +#ifdef CC_USE_GLES3 gles3wLoadProcs(getProcAddress); - - gLibEGL = std::move(libEGL); - gLibGLES = std::move(libGLES); +#endif return true; } } // namespace diff --git a/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp b/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp index eb91990b070..54fe5571c4a 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp +++ b/native/cocos/renderer/gfx-gles-common/egl/Surface.cpp @@ -1,14 +1,18 @@ #include "Surface.h" +#include "gfx-gles-common/egl/Debug.h" namespace cc::gfx::egl { - bool PBufferSurface::init(EGLConfig cfg, const EGLint *attributes) { EGL_CHECK(_surface = eglCreatePbufferSurface(eglGetDisplay(EGL_DEFAULT_DISPLAY), cfg, attributes)); return _surface != EGL_NO_SURFACE; } -bool WindowSurface::init(EGLConfig cfg, void *window) { - EGL_CHECK(_surface = eglCreateWindowSurface(_display, cfg, reinterpret_cast(window), nullptr)); +void WindowSurface::swapBuffer() { + EGL_CHECK(eglSwapBuffers(_display, _surface)); +} + +bool WindowSurface::init(EGLConfig cfg, EGLNativeWindowType window) { + EGL_CHECK(_surface = eglCreateWindowSurface(_display, cfg, window, nullptr)); eglQuerySurface(_display, _surface, EGL_WIDTH, &_width); eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height); diff --git a/native/cocos/renderer/gfx-gles-common/egl/Surface.h b/native/cocos/renderer/gfx-gles-common/egl/Surface.h index fd05b99f443..0e06484ef7c 100644 --- a/native/cocos/renderer/gfx-gles-common/egl/Surface.h +++ b/native/cocos/renderer/gfx-gles-common/egl/Surface.h @@ -1,3 +1,4 @@ +#pragma once #include "gfx-gles-common/egl/Base.h" #include "gfx-base/GFXDeviceObject.h" @@ -16,7 +17,7 @@ class Surface : public GFXDeviceObject { } EGLSurface getNativeHandle() const { return _surface; }; - void swapBuffer() { eglSwapBuffers(_display, _surface); }; + virtual void swapBuffer() {}; protected: EGLDisplay _display = EGL_NO_DISPLAY; @@ -28,7 +29,8 @@ class WindowSurface : public Surface { WindowSurface() = default; ~WindowSurface() override = default; - bool init(EGLConfig cfg, void *window); + bool init(EGLConfig cfg, EGLNativeWindowType window); + void swapBuffer() override; EGLint getWidth() const { return _width; } EGLint getHeight() const { return _height; } diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.cpp b/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.cpp new file mode 100644 index 00000000000..69cb047fe28 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.cpp @@ -0,0 +1,6 @@ +#include "GLES2CommandEncoder.h" + +namespace cc::gfx { + + +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.h b/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.h new file mode 100644 index 00000000000..7db9ec55bbf --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2CommandEncoder.h @@ -0,0 +1,12 @@ +#pragma once + +#include "gfx-gles-common/common/GLESCommandEncoder.h" + +namespace cc::gfx { + +class GLES2CommandEncoder : public GLESCommandEncoder { +public: + GLES2CommandEncoder() = default; + ~GLES2CommandEncoder() override = default; +}; +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.cpp b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.cpp new file mode 100644 index 00000000000..cd4aab8860a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.cpp @@ -0,0 +1,33 @@ +#include "GLES2Commands.h" + +namespace cc::gfx { + +#include "GLES2Types.inl" + +void cmdFuncGLES2CreateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer) {} +void cmdFuncGLES2DestroyBuffer(GLESDevice *device, GLuint *bufferIDs, uint32_t count) {} +void cmdFuncGLES2ResizeBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer) {} +void cmdFuncGLES2UpdateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer, const void *buffer, uint32_t offset, uint32_t size, bool useMap, bool sync) {} +void cmdFuncGLES2CreateTexture(GLESDevice *device, GLESGPUTexture *gpuTexture) {} +void cmdFuncGLES2DestroyTexture(GLESDevice *device, GLuint *texIDs, uint32_t count) {} +void cmdFuncGLES2DestroyRenderBuffer(GLESDevice *device, GLuint *renderbufferIDs, uint32_t count) {} +void cmdFuncGLES2ResizeTexture(GLESDevice *device, GLESGPUTexture *gpuTexture) {} +void cmdFuncGLES2UpdateProgramBinaryFormats(GLESDevice *device, ccstd::vector &formats) {} +void cmdFuncGLES2CreateShaderByBinary(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash) {} +void cmdFuncGLES2CreateShaderBySource(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash) {} +void cmdFuncGLES2DestroyProgram(GLESDevice *device, GLuint programID) {} +void cmdFuncGLES2CreatePipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso) {} +void cmdFuncGLES2DestroyPipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso) {} +void cmdFuncGLES2CreateRenderPass(GLESDevice *device, GLESGPURenderPass *gpuRenderPass) {} +void cmdFuncGLES2CreateInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler) {} +void cmdFuncGLES2DestroyInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler) {} +void cmdFuncGLES2CreateFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex) {} +void cmdFuncGLES2DestroyFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex) {} +void cmdFuncGLES2CreateGeneralBarrier(GLESDevice *device, GLESGPUGeneralBarrier *barrier) {} +void cmdFuncGLES2CopyBuffersToTexture(GLESDevice *device, const uint8_t *const *buffers, GLESGPUTexture *gpuTexture, const BufferTextureCopy *regions, uint32_t count) {} +void cmdFuncGLES2CreateSampler(GLESDevice *device, GLESGPUSampler *gpuSampler) {} +void cmdFuncGLES2DestroySampler(GLESDevice *device, GLESGPUSampler *gpuSampler) {} +void cmdFuncGLES2CreateFence(GLESDevice *device, GLESGPUFence *gpuFence) {} +void cmdFuncGLES2DestroyFence(GLESDevice *device, GLESGPUFence *gpuFence) {} +void cmdFuncGLES2WaitFence(GLESDevice *device, GLESGPUFence *gpuFence, uint64_t timeout, bool isClient) {} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.h b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.h new file mode 100644 index 00000000000..287b5bd4f8e --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Commands.h @@ -0,0 +1,53 @@ +#pragma once + +#include "gfx-gles-common/common/GLESBase.h" +#include "gfx-gles-common/common/GLESDevice.h" +#include "gfx-gles-common/common/GLESInputAssembler.h" +#include "gfx-gles-common/common/GLESFramebuffer.h" +#include "gfx-gles-common/common/GLESCommandEncoder.h" + +namespace cc::gfx { +struct GLESGPUFence; + +void cmdFuncGLES2UpdateFormatFeatures(GLESDevice *device, ccstd::array(Format::COUNT)> &formatFeatures); +void cmdFuncGLES2UpdateTextureExclusive(GLESDevice *device, ccstd::array(Format::COUNT)> &textureExclusive); +void cmdFuncGLES2UpdateFeatureAndCapabilities(GLESDevice *device, DeviceCaps &caps, GLESGPUConstantRegistry &constantRegistry, + ccstd::array(Feature::COUNT)> &features); + +void cmdFuncGLES2CreateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +void cmdFuncGLES2ResizeBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +void cmdFuncGLES3UpdateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer, const void *buffer, uint32_t offset, uint32_t size, bool useMap, bool sync); +void cmdFuncGLES2DestroyBuffer(GLESDevice *device, GLuint *bufferIDs, uint32_t count); + +void cmdFuncGLES2CreateTexture(GLESDevice *device, GLESGPUTexture *gpuTexture); +void cmdFuncGLES2ResizeTexture(GLESDevice *device, GLESGPUTexture *gpuTexture); +void cmdFuncGLES2DestroyTexture(GLESDevice *device, GLuint *texIDs, uint32_t count); +void cmdFuncGLES2DestroyRenderBuffer(GLESDevice *device, GLuint *renderbufferIDs, uint32_t count); + +void cmdFuncGLES2UpdateProgramBinaryFormats(GLESDevice *device, ccstd::vector &formats); +void cmdFuncGLES2CreateShaderByBinary(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +void cmdFuncGLES2CreateShaderBySource(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +void cmdFuncGLES2DestroyProgram(GLESDevice *device, GLuint programID); + +void cmdFuncGLES2CreatePipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso); +void cmdFuncGLES2DestroyPipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso); + +void cmdFuncGLES2CreateRenderPass(GLESDevice *device, GLESGPURenderPass *gpuRenderPass); + +void cmdFuncGLES2CreateInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); +void cmdFuncGLES2DestroyInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); + +void cmdFuncGLES2CreateFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); +void cmdFuncGLES2DestroyFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); + +void cmdFuncGLES2CreateSampler(GLESDevice *device, GLESGPUSampler *gpuSampler); +void cmdFuncGLES2DestroySampler(GLESDevice *device, GLESGPUSampler *gpuSampler); + +void cmdFuncGLES2CreateFence(GLESDevice *device, GLESGPUFence *gpuFence); +void cmdFuncGLES2DestroyFence(GLESDevice *device, GLESGPUFence *gpuFence); +void cmdFuncGLES2WaitFence(GLESDevice *device, GLESGPUFence *gpuFence, uint64_t timeout, bool isClient); + +void cmdFuncGLES2CreateGeneralBarrier(GLESDevice *device, GLESGPUGeneralBarrier *barrier); + +void cmdFuncGLES2CopyBuffersToTexture(GLESDevice *device, const uint8_t *const *buffers, GLESGPUTexture *gpuTexture, const BufferTextureCopy *regions, uint32_t count); +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2Features.cpp b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Features.cpp new file mode 100644 index 00000000000..a73dc664f7e --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Features.cpp @@ -0,0 +1,280 @@ +#include "GLES2Commands.h" + +namespace cc::gfx { +#define ENABLE_GLES2_SUBPASS +#define ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP 1 + +void cmdFuncGLES2UpdateFormatFeatures(GLESDevice *device, ccstd::array(Format::COUNT)> &formatFeatures) { + const FormatFeature completeFeature = FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE | FormatFeature::LINEAR_FILTER; + + // builtin formatFeatures + formatFeatures[toNumber(Format::RGB8)] = completeFeature; + formatFeatures[toNumber(Format::R5G6B5)] = completeFeature; + + formatFeatures[toNumber(Format::RGBA8)] = completeFeature; + formatFeatures[toNumber(Format::RGBA4)] = completeFeature; + + formatFeatures[toNumber(Format::RGB5A1)] = completeFeature; + + formatFeatures[toNumber(Format::R8)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG8)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB8)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA8)] |= FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R8I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG8I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB8I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA8I)] |= FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R8UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG8UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB8UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA8UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R16I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG16I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB16I)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA16I)] |= FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R16UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG16UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB16UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA16UI)] |= FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R32F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::VERTEX_ATTRIBUTE; + + if (device->checkExtension("OES_vertex_half_float")) { + formatFeatures[toNumber(Format::R16F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::VERTEX_ATTRIBUTE; + formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::VERTEX_ATTRIBUTE; + } + + formatFeatures[toNumber(Format::DEPTH)] |= FormatFeature::RENDER_TARGET; + formatFeatures[toNumber(Format::DEPTH_STENCIL)] |= FormatFeature::RENDER_TARGET; + + if (device->checkExtension("EXT_sRGB")) { + formatFeatures[toNumber(Format::SRGB8)] |= completeFeature; + formatFeatures[toNumber(Format::SRGB8_A8)] |= completeFeature; + } + + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R8)] |= completeFeature; + formatFeatures[toNumber(Format::RG8)] |= completeFeature; + } + + if (device->checkExtension("texture_float")) { + formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R32F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + } + } + + if (device->checkExtension("texture_half_float")) { + formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R16F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE; + } + } + + if (device->checkExtension("color_buffer_half_float")) { + formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::RENDER_TARGET; + formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::RENDER_TARGET; + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R16F)] |= FormatFeature::RENDER_TARGET; + formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::RENDER_TARGET; + } + } + + if (device->checkExtension("texture_float_linear")) { + formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::LINEAR_FILTER; + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R32F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::LINEAR_FILTER; + } + } + + if (device->checkExtension("OES_texture_half_float_linear")) { + formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::LINEAR_FILTER; + if (device->checkExtension("texture_rg")) { + formatFeatures[toNumber(Format::R16F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::LINEAR_FILTER; + } + } + + if (device->checkExtension("depth_texture")) { + formatFeatures[toNumber(Format::DEPTH)] |= completeFeature; + } + + if (device->checkExtension("packed_depth_stencil")) { + formatFeatures[toNumber(Format::DEPTH_STENCIL)] |= completeFeature; + } + + // compressed texture feature + const FormatFeature compressedFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::LINEAR_FILTER; + if (device->checkExtension("compressed_ETC1")) { + formatFeatures[toNumber(Format::ETC_RGB8)] |= compressedFeature; + } + + if (device->checkExtension("texture_compression_pvrtc")) { + formatFeatures[toNumber(Format::PVRTC_RGB2)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGBA2)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGB4)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGBA4)] |= compressedFeature; + } + + if (device->checkExtension("texture_compression_astc")) { + formatFeatures[toNumber(Format::ASTC_RGBA_4X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_5X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_5X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_6X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_6X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_12X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_12X12)] |= compressedFeature; + + formatFeatures[toNumber(Format::ASTC_SRGBA_4X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_5X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_5X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_6X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_6X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_12X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_12X12)] |= compressedFeature; + } +} + +void cmdFuncGLES2UpdateTextureExclusive(GLESDevice *device, ccstd::array(Format::COUNT)> &textureExclusive) { + textureExclusive.fill(true); + + // builtin formatFeatures + textureExclusive[toNumber(Format::R5G6B5)] = false; + textureExclusive[toNumber(Format::RGBA4)] = false; + textureExclusive[toNumber(Format::RGB5A1)] = false; + textureExclusive[toNumber(Format::DEPTH)] = false; + textureExclusive[toNumber(Format::DEPTH_STENCIL)] = false; + + if (device->checkExtension("EXT_sRGB")) { + textureExclusive[toNumber(Format::SRGB8_A8)] = false; + } + + if (device->checkExtension("color_buffer_half_float")) { + textureExclusive[toNumber(Format::RGB16F)] = false; + textureExclusive[toNumber(Format::RGBA16F)] = false; + if (device->checkExtension("texture_rg")) { + textureExclusive[toNumber(Format::R16F)] = false; + textureExclusive[toNumber(Format::RG16F)] = false; + } + } +} + +void cmdFuncGLES2UpdateFeatureAndCapabilities(GLESDevice *device, DeviceCaps &caps, GLESGPUConstantRegistry &constantRegistry, ccstd::array(Feature::COUNT)> &features) { + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, reinterpret_cast(&caps.maxVertexAttributes)); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, reinterpret_cast(&caps.maxVertexUniformVectors)); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, reinterpret_cast(&caps.maxFragmentUniformVectors)); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, reinterpret_cast(&caps.maxTextureUnits)); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, reinterpret_cast(&caps.maxVertexTextureUnits)); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, reinterpret_cast(&caps.maxTextureSize)); + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, reinterpret_cast(&caps.maxCubeMapTextureSize)); + caps.uboOffsetAlignment = 16; + + constantRegistry.useVAO = device->checkExtension("vertex_array_object"); + constantRegistry.useDrawInstanced = device->checkExtension("draw_instanced"); + constantRegistry.useInstancedArrays = device->checkExtension("instanced_arrays"); + constantRegistry.useDiscardFramebuffer = device->checkExtension("discard_framebuffer"); + + features[toNumber(Feature::INSTANCED_ARRAYS)] = constantRegistry.useInstancedArrays; + features[toNumber(Feature::ELEMENT_INDEX_UINT)] = device->checkExtension("element_index_uint"); + features[toNumber(Feature::BLEND_MINMAX)] = device->checkExtension("blend_minmax"); + + if (device->checkExtension("draw_buffers")) { + features[toNumber(Feature::MULTIPLE_RENDER_TARGETS)] = true; + glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, reinterpret_cast(&caps.maxColorRenderTargets)); + } + + if (device->checkExtension("GL_OES_texture_3D")) { + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, reinterpret_cast(&caps.max3DTextureSize)); + // texture2DArray fallback to texture3DOES + caps.maxArrayTextureLayers = caps.max3DTextureSize; + } + + ccstd::string fbfLevelStr = "NONE"; +#ifdef ENABLE_GLES2_SUBPASS + if (device->checkExtension("framebuffer_fetch")) { + if (device->checkExtension(CC_TOSTR(GL_EXT_shader_framebuffer_fetch_non_coherent))) { + constantRegistry.mFBF = FBFSupportLevel::NON_COHERENT_EXT; + features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true; + fbfLevelStr = "NON_COHERENT_EXT"; + } else if (device->checkExtension(CC_TOSTR(GL_QCOM_shader_framebuffer_fetch_noncoherent))) { + constantRegistry.mFBF = FBFSupportLevel::NON_COHERENT_QCOM; + features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true; + fbfLevelStr = "NON_COHERENT_QCOM"; + } else { + // we only care about EXT_shader_framebuffer_fetch, the ARM version does not support MRT + constantRegistry.mFBF = FBFSupportLevel::COHERENT; + fbfLevelStr = "COHERENT"; + } + + features[toNumber(Feature::INPUT_ATTACHMENT_BENEFIT)] = true; + features[toNumber(Feature::SUBPASS_COLOR_INPUT)] = true; + } + + if (device->checkExtension(CC_TOSTR(ARM_shader_framebuffer_fetch_depth_stencil))) { + features[toNumber(Feature::SUBPASS_DEPTH_STENCIL_INPUT)] = true; + fbfLevelStr += "_DEPTH_STENCIL"; + } + constantRegistry.fbfLevelStr = fbfLevelStr; +#endif + + ccstd::string msaaLevelStr = "NONE"; +#if CC_PLATFORM != CC_PLATFORM_WINDOWS || ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP + if (device->checkExtension("multisampled_render_to_texture")) { + if (device->checkExtension("multisampled_render_to_texture2")) { + constantRegistry.mMSRT = MSRTSupportLevel::LEVEL2; + msaaLevelStr = "MSRT2"; + } else { + constantRegistry.mMSRT = MSRTSupportLevel::LEVEL1; + msaaLevelStr = "MSRT1"; + } + } +#endif + constantRegistry.msaaLevelStr = msaaLevelStr; + features[toNumber(Feature::MULTI_SAMPLE_RESOLVE_DEPTH_STENCIL)] = false; // not implement yet. + + // compressed feature + ccstd::string compressedFmts; + if (device->getFormatFeatures(Format::ETC_RGB8) != FormatFeature::NONE) { + compressedFmts += "etc1 "; + } + + if (device->getFormatFeatures(Format::PVRTC_RGB2) != FormatFeature::NONE) { + compressedFmts += "pvrtc "; + } + + if (device->getFormatFeatures(Format::ASTC_RGBA_4X4) != FormatFeature::NONE) { + compressedFmts += "astc "; + } +} + +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/gles2/GLES2Types.inl b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Types.inl new file mode 100644 index 00000000000..b9509338c53 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles2/GLES2Types.inl @@ -0,0 +1,330 @@ +namespace { +GLenum mapGLFormat(Format format) { + switch (format) { + case Format::A8: return GL_ALPHA; + case Format::L8: return GL_LUMINANCE; + case Format::LA8: return GL_LUMINANCE_ALPHA; + + case Format::R8: + case Format::R8SN: + case Format::R16F: + case Format::R32F: return GL_RED_EXT; + case Format::RG8: + case Format::RG8SN: + case Format::RG16F: + case Format::RG32F: return GL_RG_EXT; + case Format::RGB8: + case Format::RGB8SN: + case Format::RGB16F: + case Format::RGB32F: + case Format::R5G6B5: + case Format::SRGB8: return GL_RGB; + case Format::RGBA8: + case Format::RGBA8SN: + case Format::RGBA16F: + case Format::RGBA32F: + case Format::RGBA4: + case Format::RGB5A1: + case Format::RGB10A2: + case Format::SRGB8_A8: return GL_RGBA; + + case Format::DEPTH: return GL_DEPTH_COMPONENT; + case Format::DEPTH_STENCIL: return GL_DEPTH_STENCIL_OES; + + case Format::BC1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case Format::BC1_ALPHA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case Format::BC1_SRGB: return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + case Format::BC1_SRGB_ALPHA: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + case Format::BC2: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case Format::BC2_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + case Format::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case Format::BC3_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + + case Format::ETC_RGB8: return GL_ETC1_RGB8_OES; + + case Format::PVRTC_RGB2: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGBA2: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGB4: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + case Format::PVRTC_RGBA4: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + + case Format::ASTC_RGBA_4X4: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + case Format::ASTC_RGBA_5X4: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR; + case Format::ASTC_RGBA_5X5: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR; + case Format::ASTC_RGBA_6X5: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR; + case Format::ASTC_RGBA_6X6: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR; + case Format::ASTC_RGBA_8X5: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR; + case Format::ASTC_RGBA_8X6: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR; + case Format::ASTC_RGBA_8X8: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + case Format::ASTC_RGBA_10X5: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + case Format::ASTC_RGBA_10X6: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + case Format::ASTC_RGBA_10X8: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + case Format::ASTC_RGBA_10X10: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + case Format::ASTC_RGBA_12X10: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + case Format::ASTC_RGBA_12X12: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + + case Format::ASTC_SRGBA_4X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; + case Format::ASTC_SRGBA_5X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; + case Format::ASTC_SRGBA_5X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; + case Format::ASTC_SRGBA_6X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; + case Format::ASTC_SRGBA_6X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; + case Format::ASTC_SRGBA_8X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; + case Format::ASTC_SRGBA_8X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + case Format::ASTC_SRGBA_8X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + case Format::ASTC_SRGBA_10X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + case Format::ASTC_SRGBA_10X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + case Format::ASTC_SRGBA_10X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + case Format::ASTC_SRGBA_10X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + case Format::ASTC_SRGBA_12X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + case Format::ASTC_SRGBA_12X12: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; + + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +GLenum mapGLInternalFormat(Format format) { + switch (format) { + case Format::R8: return GL_R8_EXT; + case Format::RG8: return GL_RG8_EXT; + case Format::SRGB8: return GL_SRGB_EXT; + case Format::SRGB8_A8: return GL_SRGB_ALPHA_EXT; + case Format::R16F: return GL_R16F_EXT; + case Format::RG16F: return GL_RG16F_EXT; + case Format::RGB16F: return GL_RGB16F_EXT; + case Format::RGBA16F: return GL_RGBA16F_EXT; + case Format::R32F: return GL_R32F_EXT; + case Format::RG32F: return GL_RG32F_EXT; + case Format::RGB32F: return GL_RGB32F_EXT; + case Format::RGBA32F: return GL_RGBA32F_EXT; + case Format::R5G6B5: return GL_RGB565; + case Format::RGB5A1: return GL_RGB5_A1; + case Format::RGBA4: return GL_RGBA4; + case Format::DEPTH: return GL_DEPTH_COMPONENT16; + case Format::DEPTH_STENCIL: return GL_DEPTH24_STENCIL8_OES; + + default: return mapGLFormat(format); + } +} + +GLenum mapGLType(Type type) { + switch (type) { + case Type::BOOL: return GL_BOOL; + case Type::BOOL2: return GL_BOOL_VEC2; + case Type::BOOL3: return GL_BOOL_VEC3; + case Type::BOOL4: return GL_BOOL_VEC4; + case Type::INT: return GL_INT; + case Type::INT2: return GL_INT_VEC2; + case Type::INT3: return GL_INT_VEC3; + case Type::INT4: return GL_INT_VEC4; + case Type::UINT: return GL_UNSIGNED_INT; + case Type::FLOAT: return GL_FLOAT; + case Type::FLOAT2: return GL_FLOAT_VEC2; + case Type::FLOAT3: return GL_FLOAT_VEC3; + case Type::FLOAT4: return GL_FLOAT_VEC4; + case Type::MAT2: return GL_FLOAT_MAT2; + case Type::MAT3: return GL_FLOAT_MAT3; + case Type::MAT4: return GL_FLOAT_MAT4; + case Type::SAMPLER2D: return GL_SAMPLER_2D; + case Type::SAMPLER3D: return GL_SAMPLER_3D_OES; + case Type::SAMPLER_CUBE: return GL_SAMPLER_CUBE; + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +Type mapType(GLenum glType) { + switch (glType) { + case GL_BOOL: return Type::BOOL; + case GL_BOOL_VEC2: return Type::BOOL2; + case GL_BOOL_VEC3: return Type::BOOL3; + case GL_BOOL_VEC4: return Type::BOOL4; + case GL_INT: return Type::INT; + case GL_INT_VEC2: return Type::INT2; + case GL_INT_VEC3: return Type::INT3; + case GL_INT_VEC4: return Type::INT4; + case GL_UNSIGNED_INT: return Type::UINT; + case GL_FLOAT: return Type::FLOAT; + case GL_FLOAT_VEC2: return Type::FLOAT2; + case GL_FLOAT_VEC3: return Type::FLOAT3; + case GL_FLOAT_VEC4: return Type::FLOAT4; + case GL_FLOAT_MAT2: return Type::MAT2; + case GL_FLOAT_MAT3: return Type::MAT3; + case GL_FLOAT_MAT4: return Type::MAT4; + case GL_SAMPLER_2D: return Type::SAMPLER2D; + case GL_SAMPLER_3D_OES: return Type::SAMPLER3D; + case GL_SAMPLER_CUBE: return Type::SAMPLER_CUBE; + default: { + CC_ABORT(); + return Type::UNKNOWN; + } + } +} + +GLenum formatToGLType(Format format) { + switch (format) { + case Format::R8: return GL_UNSIGNED_BYTE; + case Format::R8SN: return GL_BYTE; + case Format::R8UI: return GL_UNSIGNED_BYTE; + case Format::R8I: return GL_BYTE; + case Format::R16F: return GL_HALF_FLOAT_OES; + case Format::R16UI: return GL_UNSIGNED_SHORT; + case Format::R16I: return GL_SHORT; + case Format::R32F: return GL_FLOAT; + case Format::R32UI: return GL_UNSIGNED_INT; + case Format::R32I: return GL_INT; + + case Format::RG8: return GL_UNSIGNED_BYTE; + case Format::RG8SN: return GL_BYTE; + case Format::RG8UI: return GL_UNSIGNED_BYTE; + case Format::RG8I: return GL_BYTE; + case Format::RG16F: return GL_HALF_FLOAT_OES; + case Format::RG16UI: return GL_UNSIGNED_SHORT; + case Format::RG16I: return GL_SHORT; + case Format::RG32F: return GL_FLOAT; + case Format::RG32UI: return GL_UNSIGNED_INT; + case Format::RG32I: return GL_INT; + + case Format::RGB8: + case Format::SRGB8: return GL_UNSIGNED_BYTE; + case Format::RGB8SN: return GL_BYTE; + case Format::RGB8UI: return GL_UNSIGNED_BYTE; + case Format::RGB8I: return GL_BYTE; + case Format::RGB16F: return GL_HALF_FLOAT_OES; + case Format::RGB16UI: return GL_UNSIGNED_SHORT; + case Format::RGB16I: return GL_SHORT; + case Format::RGB32F: return GL_FLOAT; + case Format::RGB32UI: return GL_UNSIGNED_INT; + case Format::RGB32I: return GL_INT; + + case Format::RGBA8: + case Format::SRGB8_A8: return GL_UNSIGNED_BYTE; + case Format::RGBA8SN: return GL_BYTE; + case Format::RGBA8UI: return GL_UNSIGNED_BYTE; + case Format::RGBA8I: return GL_BYTE; + case Format::RGBA16F: return GL_HALF_FLOAT_OES; + case Format::RGBA16UI: return GL_UNSIGNED_SHORT; + case Format::RGBA16I: return GL_SHORT; + case Format::RGBA32F: return GL_FLOAT; + case Format::RGBA32UI: return GL_UNSIGNED_INT; + case Format::RGBA32I: return GL_INT; + + case Format::R5G6B5: return GL_UNSIGNED_SHORT_5_6_5; + case Format::RGB5A1: return GL_UNSIGNED_SHORT_5_5_5_1; + case Format::RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; + case Format::RGB9E5: return GL_FLOAT; + + case Format::DEPTH: return GL_UNSIGNED_SHORT; + case Format::DEPTH_STENCIL: return GL_UNSIGNED_INT_24_8_OES; + + case Format::BC1: + case Format::BC1_SRGB: + case Format::BC2: + case Format::BC2_SRGB: + case Format::BC3: + case Format::BC3_SRGB: + case Format::BC4: return GL_UNSIGNED_BYTE; + case Format::BC4_SNORM: return GL_BYTE; + case Format::BC5: return GL_UNSIGNED_BYTE; + case Format::BC5_SNORM: return GL_BYTE; + case Format::BC6H_SF16: + case Format::BC6H_UF16: return GL_FLOAT; + case Format::BC7: + case Format::BC7_SRGB: + + case Format::ETC_RGB8: + case Format::EAC_R11: return GL_UNSIGNED_BYTE; + case Format::EAC_R11SN: return GL_BYTE; + case Format::EAC_RG11: return GL_UNSIGNED_BYTE; + case Format::EAC_RG11SN: return GL_BYTE; + + case Format::PVRTC_RGB2: + case Format::PVRTC_RGBA2: + case Format::PVRTC_RGB4: + case Format::PVRTC_RGBA4: + case Format::PVRTC2_2BPP: + case Format::PVRTC2_4BPP: + + case Format::ASTC_RGBA_4X4: + case Format::ASTC_RGBA_5X4: + case Format::ASTC_RGBA_5X5: + case Format::ASTC_RGBA_6X5: + case Format::ASTC_RGBA_6X6: + case Format::ASTC_RGBA_8X5: + case Format::ASTC_RGBA_8X6: + case Format::ASTC_RGBA_8X8: + case Format::ASTC_RGBA_10X5: + case Format::ASTC_RGBA_10X6: + case Format::ASTC_RGBA_10X8: + case Format::ASTC_RGBA_10X10: + case Format::ASTC_RGBA_12X10: + case Format::ASTC_RGBA_12X12: + case Format::ASTC_SRGBA_4X4: + case Format::ASTC_SRGBA_5X4: + case Format::ASTC_SRGBA_5X5: + case Format::ASTC_SRGBA_6X5: + case Format::ASTC_SRGBA_6X6: + case Format::ASTC_SRGBA_8X5: + case Format::ASTC_SRGBA_8X6: + case Format::ASTC_SRGBA_8X8: + case Format::ASTC_SRGBA_10X5: + case Format::ASTC_SRGBA_10X6: + case Format::ASTC_SRGBA_10X8: + case Format::ASTC_SRGBA_10X10: + case Format::ASTC_SRGBA_12X10: + case Format::ASTC_SRGBA_12X12: + return GL_UNSIGNED_BYTE; + + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +uint32_t glTypeSize(GLenum glType) { + switch (glType) { + case GL_BOOL: return 4; + case GL_BOOL_VEC2: return 8; + case GL_BOOL_VEC3: return 12; + case GL_BOOL_VEC4: return 16; + case GL_INT: return 4; + case GL_INT_VEC2: return 8; + case GL_INT_VEC3: return 12; + case GL_INT_VEC4: return 16; + case GL_UNSIGNED_INT: + case GL_FLOAT: return 4; + case GL_FLOAT_VEC2: return 8; + case GL_FLOAT_VEC3: return 12; + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: return 16; + case GL_FLOAT_MAT3: return 36; + case GL_FLOAT_MAT4: return 64; + case GL_SAMPLER_2D: + case GL_SAMPLER_3D_OES: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_MAP_ARRAY_OES: + case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES: + case GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES: + case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES: return 4; + default: { + CC_ABORT(); + return 0; + } + } +} + +uint32_t glComponentCount(GLenum glType) { + switch (glType) { + case GL_FLOAT_MAT2: return 2; + case GL_FLOAT_MAT3: return 3; + case GL_FLOAT_MAT4: return 4; + default: { + return 1; + } + } +} +} // namespace \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.cpp b/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.cpp new file mode 100644 index 00000000000..4c14ac155ec --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.cpp @@ -0,0 +1,756 @@ +#include "GLES3CommandEncoder.h" + +#include "gfx-gles-common/loader/gles2w.h" +#include "gfx-gles-common/loader/gles3w.h" + +#include "gfx-gles-common/egl/Context.h" + +#include "gfx-gles-common/egl/Debug.h" +#include "gfx-gles-common/common/GLESDevice.h" +#include "gfx-gles-common/common/GLESRenderPass.h" +#include "GLES3Commands.h" + +namespace cc::gfx { +#define BUFFER_OFFSET(idx) (static_cast(0) + (idx)) + +namespace { +void makeCurrent(egl::Context *context, FBOProxy &fboProxy) { + if (fboProxy.fbo.swapchain != nullptr) { + context->makeCurrent(fboProxy.fbo.swapchain->surface->getNativeHandle()); + } +} + +void doResolve(egl::Context *context, GLESGPUStateCache *cache, GLESGPUFramebuffer *gpuFbo) { + auto framebuffer = FBOProxy(gpuFbo->framebuffer, context->getContextID()); + auto resolveFramebuffer = FBOProxy(gpuFbo->resolveFramebuffer, context->getContextID()); + makeCurrent(context, resolveFramebuffer); + + auto width = gpuFbo->width; + auto height = gpuFbo->height; + + if (cache->readFrameBuffer != framebuffer.handle) { + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.handle)); + cache->readFrameBuffer = framebuffer.handle; + } + + if (cache->drawFrameBuffer != resolveFramebuffer.handle) { + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFramebuffer.handle)); + cache->drawFrameBuffer = resolveFramebuffer.handle; + } + + resolveFramebuffer.processLoad(GL_DRAW_FRAMEBUFFER); + + if (!gpuFbo->colorBlitPairs.empty()) { + auto resolveColorNum = gpuFbo->resolveFramebuffer.colors.size(); + std::vector drawBuffers(resolveColorNum, GL_NONE); + for (auto &[src, dst] : gpuFbo->colorBlitPairs) { + drawBuffers[dst] = GL_COLOR_ATTACHMENT0 + dst; + GL_CHECK(glReadBuffer(GL_COLOR_ATTACHMENT0 + src)); + if (resolveFramebuffer.handle != 0) { + GL_CHECK(glDrawBuffers(resolveColorNum, drawBuffers.data())); + } + + GL_CHECK(glBlitFramebuffer( + 0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST)); + drawBuffers[dst] = GL_NONE; + } + } + if (gpuFbo->dsResolveMask != 0 && resolveFramebuffer.handle != 0) { + GL_CHECK(glBlitFramebuffer( + 0, 0, width, height, + 0, 0, width, height, + gpuFbo->dsResolveMask, GL_NEAREST)); + } + + framebuffer.processStore(GL_READ_FRAMEBUFFER); + resolveFramebuffer.processStore(GL_DRAW_FRAMEBUFFER); +} + +const GLenum GLES3_CMP_FUNCS[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS, +}; +const GLenum GLES3_STENCIL_OPS[] = { + GL_ZERO, + GL_KEEP, + GL_REPLACE, + GL_INCR, + GL_DECR, + GL_INVERT, + GL_INCR_WRAP, + GL_DECR_WRAP, +}; + +const GLenum GLES3_BLEND_OPS[] = { + GL_FUNC_ADD, + GL_FUNC_SUBTRACT, + GL_FUNC_REVERSE_SUBTRACT, + GL_MIN, + GL_MAX, +}; + +const GLenum GLES3_BLEND_FACTORS[] = { + GL_ZERO, + GL_ONE, + GL_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_SRC_COLOR, + GL_DST_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + GL_CONSTANT_COLOR, + GL_ONE_MINUS_CONSTANT_COLOR, + GL_CONSTANT_ALPHA, + GL_ONE_MINUS_CONSTANT_ALPHA, +}; + +bool isDynamicBuffer(DescriptorType type) { + return type == DescriptorType::DYNAMIC_STORAGE_BUFFER || + type == DescriptorType::DYNAMIC_UNIFORM_BUFFER; +}; + +bool isBufferType(DescriptorType type) { + return type == DescriptorType::UNIFORM_BUFFER || + type == DescriptorType::DYNAMIC_UNIFORM_BUFFER || + type == DescriptorType::STORAGE_BUFFER || + type == DescriptorType::DYNAMIC_STORAGE_BUFFER; +} + +bool isTextureSampler(DescriptorType type) { + return type == DescriptorType::SAMPLER_TEXTURE || + type == DescriptorType::SAMPLER || + type == DescriptorType::TEXTURE || + type == DescriptorType::STORAGE_IMAGE; +} + +bool checkBuffer(const GLESGPUDescriptor &desc) { + return desc.gpuBufferView && + desc.gpuBufferView->gpuBuffer && + desc.gpuBufferView->gpuBuffer->glBuffer != 0 && + desc.gpuBufferView->range != 0; +} + +bool checkTexture(const GLESGPUDescriptor &desc) { + return desc.gpuTextureView && + desc.gpuTextureView->texture && + desc.gpuTextureView->texture->glTexture != 0; +} +GLenum getBufferTarget(DescriptorType type) { + switch (type) { + case DescriptorType::STORAGE_BUFFER: + case DescriptorType::DYNAMIC_STORAGE_BUFFER: + return GL_SHADER_STORAGE_BUFFER; + case DescriptorType::UNIFORM_BUFFER: + case DescriptorType::DYNAMIC_UNIFORM_BUFFER: + return GL_UNIFORM_BUFFER; + default: + break; + } + return 0; +} +} // namespace + +void GLES3CommandEncoder::beginRenderPass(const PassBeginInfo &beginInfo) { + _curSubPassIdx = 0; + + _descriptorSets.fill(nullptr); + + _currentFramebuffer = beginInfo.framebuffer; + _currentRenderPass = beginInfo.framebuffer->gpuRenderPass; + if (_currentFramebuffer == nullptr || _currentRenderPass == nullptr) { + return; + } + + auto *cache = _cacheState; + auto framebuffer = FBOProxy(_currentFramebuffer->framebuffer, _context->getContextID()); + makeCurrent(_context, framebuffer); + + if (cache->drawFrameBuffer != framebuffer.handle) { + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle)); + cache->drawFrameBuffer = framebuffer.handle; + } + + if (cache->viewport.left != beginInfo.renderArea.x || + cache->viewport.top != beginInfo.renderArea.y || + cache->viewport.width != beginInfo.renderArea.width || + cache->viewport.height != beginInfo.renderArea.height) { + GL_CHECK(glViewport(beginInfo.renderArea.x, beginInfo.renderArea.y, beginInfo.renderArea.width, beginInfo.renderArea.height)); + cache->viewport.left = beginInfo.renderArea.x; + cache->viewport.top =beginInfo.renderArea.y; + cache->viewport.width = beginInfo.renderArea.width; + cache->viewport.height = beginInfo.renderArea.height; + } + + if (cache->scissor != beginInfo.renderArea) { + GL_CHECK(glScissor(beginInfo.renderArea.x, beginInfo.renderArea.y, beginInfo.renderArea.width, beginInfo.renderArea.height)); + cache->scissor = beginInfo.renderArea; + } + + GLbitfield glClears = 0; + float fColors[4]{}; + bool maskSet = false; + + auto performLoadOp = [&](uint32_t attachmentIndex, uint32_t glAttachmentIndex) { + const ColorAttachment &colorAttachment = _currentRenderPass->colorAttachments[attachmentIndex]; + if (colorAttachment.format != Format::UNKNOWN && colorAttachment.loadOp == LoadOp::CLEAR) { + if (!maskSet && cache->bs.targets[0].blendColorMask != ColorMask::ALL) { + GL_CHECK(glColorMask(true, true, true, true)); + maskSet = true; + } + + const Color &color = beginInfo.clearColors[attachmentIndex]; + if (framebuffer.handle) { + fColors[0] = color.x; + fColors[1] = color.y; + fColors[2] = color.z; + fColors[3] = color.w; + GL_CHECK(glClearBufferfv(GL_COLOR, glAttachmentIndex, fColors)); + } else { + GL_CHECK(glClearColor(color.x, color.y, color.z, color.w)); + glClears |= GL_COLOR_BUFFER_BIT; + } + } + }; + + auto performDepthStencilLoadOp = [&](uint32_t attachmentIndex) { + if (attachmentIndex != INVALID_BINDING) { + bool hasStencils = GFX_FORMAT_INFOS[toNumber(_currentRenderPass->depthStencilAttachment.format)].hasStencil; + if (_currentRenderPass->depthStencilAttachment.depthLoadOp == LoadOp::CLEAR) { + if (!cache->dss.depthWrite) { + GL_CHECK(glDepthMask(true)); + } + GL_CHECK(glClearDepthf(beginInfo.clearDepth)); + glClears |= GL_DEPTH_BUFFER_BIT; + } + if (hasStencils && _currentRenderPass->depthStencilAttachment.depthLoadOp == LoadOp::CLEAR) { + if (!cache->dss.stencilWriteMaskFront) { + GL_CHECK(glStencilMaskSeparate(GL_FRONT, 0xffffffff)); + } + if (!cache->dss.stencilWriteMaskBack) { + GL_CHECK(glStencilMaskSeparate(GL_BACK, 0xffffffff)); + } + GL_CHECK(glClearStencil(beginInfo.clearStencil)); + glClears |= GL_STENCIL_BUFFER_BIT; + } + } + + if (glClears) { + GL_CHECK(glClear(glClears)); + } + + // restore states + if (maskSet) { + ColorMask const colorMask = cache->bs.targets[0].blendColorMask; + GL_CHECK(glColorMask((GLboolean)(colorMask & ColorMask::R), + (GLboolean)(colorMask & ColorMask::G), + (GLboolean)(colorMask & ColorMask::B), + (GLboolean)(colorMask & ColorMask::A))); + } + + if ((glClears & GL_DEPTH_BUFFER_BIT) && !cache->dss.depthWrite) { + GL_CHECK(glDepthMask(false)); + } + + if (glClears & GL_STENCIL_BUFFER_BIT) { + if (!cache->dss.stencilWriteMaskFront) { + GL_CHECK(glStencilMaskSeparate(GL_FRONT, 0)); + } + if (!cache->dss.stencilWriteMaskBack) { + GL_CHECK(glStencilMaskSeparate(GL_BACK, 0)); + } + } + }; + + const auto &attachments = _currentRenderPass->colorAttachments; + const auto &indices = _currentRenderPass->indices; + for (uint32_t i = 0; i < attachments.size(); ++i) { + performLoadOp(i, indices[i]); + } + performDepthStencilLoadOp(_currentRenderPass->depthStencil); + + framebuffer.processLoad(GL_DRAW_FRAMEBUFFER); +} + +void GLES3CommandEncoder::endRenderPass() { + + if (_currentFramebuffer->needResolve) { + doResolve(_context, _cacheState, _currentFramebuffer); + } else { + auto framebuffer = FBOProxy(_currentFramebuffer->framebuffer, _context->getContextID()); + framebuffer.processStore(GL_DRAW_FRAMEBUFFER); + } + + // no coherent support +// if (device->constantRegistry()->mFBF == FBFSupportLevel::NON_COHERENT_EXT) { +// GL_CHECK(glFramebufferFetchBarrierEXT()); +// } else if (device->constantRegistry()->mFBF == FBFSupportLevel::NON_COHERENT_QCOM) { +// GL_CHECK(glFramebufferFetchBarrierQCOM()); +// } +} + +void GLES3CommandEncoder::nextSubPass() { + ++_curSubPassIdx; +} + +void GLES3CommandEncoder::bindPipelineState(GLESGPUPipelineState *pso) { + if (_currentPipelineState == pso) { + return; + } + + _currentPipelineState = pso; + // bind rasterizer state + if (_cacheState->rs.cullMode != _currentPipelineState->rs.cullMode) { + switch (_currentPipelineState->rs.cullMode) { + case CullMode::NONE: { + if (_cacheState->isCullFaceEnabled) { + GL_CHECK(glDisable(GL_CULL_FACE)); + _cacheState->isCullFaceEnabled = false; + } + } break; + case CullMode::FRONT: { + if (!_cacheState->isCullFaceEnabled) { + GL_CHECK(glEnable(GL_CULL_FACE)); + _cacheState->isCullFaceEnabled = true; + } + GL_CHECK(glCullFace(GL_FRONT)); + } break; + case CullMode::BACK: { + if (!_cacheState->isCullFaceEnabled) { + GL_CHECK(glEnable(GL_CULL_FACE)); + _cacheState->isCullFaceEnabled = true; + } + GL_CHECK(glCullFace(GL_BACK)); + } break; + default: + break; + } + _cacheState->rs.cullMode = _currentPipelineState->rs.cullMode; + } + if (_cacheState->rs.isFrontFaceCCW != _currentPipelineState->rs.isFrontFaceCCW) { + GL_CHECK(glFrontFace(_currentPipelineState->rs.isFrontFaceCCW ? GL_CCW : GL_CW)); + _cacheState->rs.isFrontFaceCCW = _currentPipelineState->rs.isFrontFaceCCW; + } + if ((_cacheState->rs.depthBias != _currentPipelineState->rs.depthBias) || + (_cacheState->rs.depthBiasSlop != _currentPipelineState->rs.depthBiasSlop)) { + GL_CHECK(glPolygonOffset(_cacheState->rs.depthBias, _cacheState->rs.depthBiasSlop)); + _cacheState->rs.depthBiasSlop = _currentPipelineState->rs.depthBiasSlop; + } + if (_cacheState->rs.lineWidth != _currentPipelineState->rs.lineWidth) { + GL_CHECK(glLineWidth(_currentPipelineState->rs.lineWidth)); + _cacheState->rs.lineWidth = _currentPipelineState->rs.lineWidth; + } + + // bind depth-stencil state + if (_cacheState->dss.depthTest != _currentPipelineState->dss.depthTest) { + if (_currentPipelineState->dss.depthTest) { + GL_CHECK(glEnable(GL_DEPTH_TEST)); + } else { + GL_CHECK(glDisable(GL_DEPTH_TEST)); + } + _cacheState->dss.depthTest = _currentPipelineState->dss.depthTest; + } + if (_cacheState->dss.depthWrite != _currentPipelineState->dss.depthWrite) { + GL_CHECK(glDepthMask(static_cast(_currentPipelineState->dss.depthWrite))); + _cacheState->dss.depthWrite = _currentPipelineState->dss.depthWrite; + } + if (_cacheState->dss.depthFunc != _currentPipelineState->dss.depthFunc) { + GL_CHECK(glDepthFunc(GLES3_CMP_FUNCS[(int)_currentPipelineState->dss.depthFunc])); + _cacheState->dss.depthFunc = _currentPipelineState->dss.depthFunc; + } + + // bind depth-stencil state - front + if (_currentPipelineState->dss.stencilTestFront || _currentPipelineState->dss.stencilTestBack) { + if (!_cacheState->isStencilTestEnabled) { + GL_CHECK(glEnable(GL_STENCIL_TEST)); + _cacheState->isStencilTestEnabled = true; + } + } else { + if (_cacheState->isStencilTestEnabled) { + GL_CHECK(glDisable(GL_STENCIL_TEST)); + _cacheState->isStencilTestEnabled = false; + } + } + if (_cacheState->dss.stencilFuncFront != _currentPipelineState->dss.stencilFuncFront || + _cacheState->dss.stencilRefFront != _currentPipelineState->dss.stencilRefFront || + _cacheState->dss.stencilReadMaskFront != _currentPipelineState->dss.stencilReadMaskFront) { + GL_CHECK(glStencilFuncSeparate(GL_FRONT, + GLES3_CMP_FUNCS[(int)_currentPipelineState->dss.stencilFuncFront], + _currentPipelineState->dss.stencilRefFront, + _currentPipelineState->dss.stencilReadMaskFront)); + _cacheState->dss.stencilFuncFront = _currentPipelineState->dss.stencilFuncFront; + _cacheState->dss.stencilRefFront = _currentPipelineState->dss.stencilRefFront; + _cacheState->dss.stencilReadMaskFront = _currentPipelineState->dss.stencilReadMaskFront; + } + if (_cacheState->dss.stencilFailOpFront != _currentPipelineState->dss.stencilFailOpFront || + _cacheState->dss.stencilZFailOpFront != _currentPipelineState->dss.stencilZFailOpFront || + _cacheState->dss.stencilPassOpFront != _currentPipelineState->dss.stencilPassOpFront) { + GL_CHECK(glStencilOpSeparate(GL_FRONT, + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilFailOpFront], + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilZFailOpFront], + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilPassOpFront])); + _cacheState->dss.stencilFailOpFront = _currentPipelineState->dss.stencilFailOpFront; + _cacheState->dss.stencilZFailOpFront = _currentPipelineState->dss.stencilZFailOpFront; + _cacheState->dss.stencilPassOpFront = _currentPipelineState->dss.stencilPassOpFront; + } + if (_cacheState->dss.stencilWriteMaskFront != _currentPipelineState->dss.stencilWriteMaskFront) { + GL_CHECK(glStencilMaskSeparate(GL_FRONT, _currentPipelineState->dss.stencilWriteMaskFront)); + _cacheState->dss.stencilWriteMaskFront = _currentPipelineState->dss.stencilWriteMaskFront; + } + + // bind depth-stencil state - back + if (_cacheState->dss.stencilFuncBack != _currentPipelineState->dss.stencilFuncBack || + _cacheState->dss.stencilRefBack != _currentPipelineState->dss.stencilRefBack || + _cacheState->dss.stencilReadMaskBack != _currentPipelineState->dss.stencilReadMaskBack) { + GL_CHECK(glStencilFuncSeparate(GL_BACK, + GLES3_CMP_FUNCS[(int)_currentPipelineState->dss.stencilFuncBack], + _currentPipelineState->dss.stencilRefBack, + _currentPipelineState->dss.stencilReadMaskBack)); + _cacheState->dss.stencilFuncBack = _currentPipelineState->dss.stencilFuncBack; + _cacheState->dss.stencilRefBack = _currentPipelineState->dss.stencilRefBack; + _cacheState->dss.stencilReadMaskBack = _currentPipelineState->dss.stencilReadMaskBack; + } + if (_cacheState->dss.stencilFailOpBack != _currentPipelineState->dss.stencilFailOpBack || + _cacheState->dss.stencilZFailOpBack != _currentPipelineState->dss.stencilZFailOpBack || + _cacheState->dss.stencilPassOpBack != _currentPipelineState->dss.stencilPassOpBack) { + GL_CHECK(glStencilOpSeparate(GL_BACK, + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilFailOpBack], + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilZFailOpBack], + GLES3_STENCIL_OPS[(int)_currentPipelineState->dss.stencilPassOpBack])); + _cacheState->dss.stencilFailOpBack = _currentPipelineState->dss.stencilFailOpBack; + _cacheState->dss.stencilZFailOpBack = _currentPipelineState->dss.stencilZFailOpBack; + _cacheState->dss.stencilPassOpBack = _currentPipelineState->dss.stencilPassOpBack; + } + if (_cacheState->dss.stencilWriteMaskBack != _currentPipelineState->dss.stencilWriteMaskBack) { + GL_CHECK(glStencilMaskSeparate(GL_BACK, _currentPipelineState->dss.stencilWriteMaskBack)); + _cacheState->dss.stencilWriteMaskBack = _currentPipelineState->dss.stencilWriteMaskBack; + } + + // bind blend state + if (_cacheState->bs.isA2C != _currentPipelineState->bs.isA2C) { + if (_cacheState->bs.isA2C) { + GL_CHECK(glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)); + } else { + GL_CHECK(glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE)); + } + _cacheState->bs.isA2C = _currentPipelineState->bs.isA2C; + } + if (_cacheState->bs.blendColor.x != _currentPipelineState->bs.blendColor.x || + _cacheState->bs.blendColor.y != _currentPipelineState->bs.blendColor.y || + _cacheState->bs.blendColor.z != _currentPipelineState->bs.blendColor.z || + _cacheState->bs.blendColor.w != _currentPipelineState->bs.blendColor.w) { + GL_CHECK(glBlendColor(_currentPipelineState->bs.blendColor.x, + _currentPipelineState->bs.blendColor.y, + _currentPipelineState->bs.blendColor.z, + _currentPipelineState->bs.blendColor.w)); + _cacheState->bs.blendColor = _currentPipelineState->bs.blendColor; + } + + if (!_currentPipelineState->bs.targets.empty()) { + BlendTarget &cacheTarget = _cacheState->bs.targets[0]; + const BlendTarget &target = _currentPipelineState->bs.targets[0]; + if (cacheTarget.blend != target.blend) { + if (!cacheTarget.blend) { + GL_CHECK(glEnable(GL_BLEND)); + } else { + GL_CHECK(glDisable(GL_BLEND)); + } + cacheTarget.blend = target.blend; + } + if (cacheTarget.blendEq != target.blendEq || + cacheTarget.blendAlphaEq != target.blendAlphaEq) { + GL_CHECK(glBlendEquationSeparate(GLES3_BLEND_OPS[(int)target.blendEq], + GLES3_BLEND_OPS[(int)target.blendAlphaEq])); + cacheTarget.blendEq = target.blendEq; + cacheTarget.blendAlphaEq = target.blendAlphaEq; + } + if (cacheTarget.blendSrc != target.blendSrc || + cacheTarget.blendDst != target.blendDst || + cacheTarget.blendSrcAlpha != target.blendSrcAlpha || + cacheTarget.blendDstAlpha != target.blendDstAlpha) { + GL_CHECK(glBlendFuncSeparate(GLES3_BLEND_FACTORS[(int)target.blendSrc], + GLES3_BLEND_FACTORS[(int)target.blendDst], + GLES3_BLEND_FACTORS[(int)target.blendSrcAlpha], + GLES3_BLEND_FACTORS[(int)target.blendDstAlpha])); + cacheTarget.blendSrc = target.blendSrc; + cacheTarget.blendDst = target.blendDst; + cacheTarget.blendSrcAlpha = target.blendSrcAlpha; + cacheTarget.blendDstAlpha = target.blendDstAlpha; + } + if (cacheTarget.blendColorMask != target.blendColorMask) { + GL_CHECK(glColorMask((GLboolean)(target.blendColorMask & ColorMask::R), + (GLboolean)(target.blendColorMask & ColorMask::G), + (GLboolean)(target.blendColorMask & ColorMask::B), + (GLboolean)(target.blendColorMask & ColorMask::A))); + cacheTarget.blendColorMask = target.blendColorMask; + } + } + + if (_currentPipelineState->gpuShader && _cacheState->glProgram != _currentPipelineState->gpuShader->glProgram) { + GL_CHECK(glUseProgram(_currentPipelineState->gpuShader->glProgram)); + _cacheState->glProgram = _currentPipelineState->gpuShader->glProgram; + } +} + +void GLES3CommandEncoder::bindDescriptorSet(uint32_t setID, const DescriptorBindInfo &bindInfo) { + _descriptorSets[setID] = bindInfo.descriptorSet; + if (bindInfo.dynamicCount != 0) { + _dynamicOffsets[setID].resize(bindInfo.dynamicCount); + _dynamicOffsets[setID].assign(bindInfo.dynamicOffsets, bindInfo.dynamicOffsets + bindInfo.dynamicCount); + } +} + +void GLES3CommandEncoder::bindInputAssembler(GLESGPUInputAssembler *ia) { + if (_currentIA == ia) { + return; + } + _currentIA = ia; + for (auto &&glCurrentAttribLoc : _cacheState->glCurrentAttribLocs) { + glCurrentAttribLoc = false; + } + + VAOProxy proxy(*_currentIA, _context->getContextID(), _currentPipelineState->inputHash); + if (proxy.handle == 0) { + GL_CHECK(glGenVertexArrays(1, &proxy.handle)); + GL_CHECK(glBindVertexArray(proxy.handle)); + for (auto &gpuInput : _currentPipelineState->attributes) { + for (size_t a = 0; a < _currentIA->attributes.size(); ++a) { + const GLESGPUAttribute &gpuAttribute = _currentIA->glAttribs[a]; + if (gpuAttribute.name == gpuInput.name) { + GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, gpuAttribute.glBuffer)); + + for (uint32_t c = 0; c < gpuAttribute.componentCount; ++c) { + GLuint const glLoc = gpuInput.glLoc + c; + uint32_t const attribOffset = gpuAttribute.offset + gpuAttribute.size * c; + GL_CHECK(glEnableVertexAttribArray(glLoc)); + GL_CHECK(glVertexAttribPointer(glLoc, gpuAttribute.count, gpuAttribute.glType, gpuAttribute.isNormalized, gpuAttribute.stride, BUFFER_OFFSET(attribOffset))); + GL_CHECK(glVertexAttribDivisor(glLoc, gpuAttribute.isInstanced ? 1 : 0)); + _cacheState->glCurrentAttribLocs[glLoc] = true; + _cacheState->glEnabledAttribLocs[glLoc] = true; + } + break; + } + } + } + + if (_currentIA->gpuIndexBuffer) { + GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _currentIA->gpuIndexBuffer->gpuBuffer->glBuffer)); + } + + for (uint32_t a = 0; a < _cacheState->glCurrentAttribLocs.size(); ++a) { + if (_cacheState->glEnabledAttribLocs[a] != _cacheState->glCurrentAttribLocs[a]) { + GL_CHECK(glDisableVertexAttribArray(a)); + _cacheState->glEnabledAttribLocs[a] = false; + } + } + } else { + GL_CHECK(glBindVertexArray(proxy.handle)); + } +} + +void GLES3CommandEncoder::setViewport(const Viewport &vp) { + if (_cacheState->viewport != vp) { + _cacheState->viewport = vp; + GL_CHECK(glViewport(vp.left, vp.top, vp.width, vp.height)); + } +} + +void GLES3CommandEncoder::setScissor(const Rect &rect) { + if (_cacheState->scissor != rect) { + _cacheState->scissor = rect; + GL_CHECK(glScissor(rect.x, rect.y, rect.width, rect.height)); + } +} + +void GLES3CommandEncoder::setLineWidth(float width) { + if (math::isNotEqualF(_curDynamicStates.lineWidth, width)) { + _curDynamicStates.lineWidth = width; + } +} + +void GLES3CommandEncoder::setDepthBias(float constant, float clamp, float slope) { + if (math::isNotEqualF(_curDynamicStates.depthBiasConstant, constant) || + math::isNotEqualF(_curDynamicStates.depthBiasClamp, clamp) || + math::isNotEqualF(_curDynamicStates.depthBiasSlope, slope)) { + _curDynamicStates.depthBiasConstant = constant; + _curDynamicStates.depthBiasClamp = clamp; + _curDynamicStates.depthBiasSlope = slope; + } +} + +void GLES3CommandEncoder::setBlendConstants(const Color &constants) { + if (math::isNotEqualF(_curDynamicStates.blendConstant.x, constants.x) || + math::isNotEqualF(_curDynamicStates.blendConstant.y, constants.y) || + math::isNotEqualF(_curDynamicStates.blendConstant.z, constants.z) || + math::isNotEqualF(_curDynamicStates.blendConstant.w, constants.w)) { + _curDynamicStates.blendConstant.x = constants.x; + _curDynamicStates.blendConstant.y = constants.y; + _curDynamicStates.blendConstant.z = constants.z; + _curDynamicStates.blendConstant.w = constants.w; + } +} + +void GLES3CommandEncoder::setDepthBound(float minBounds, float maxBounds) { + if (math::isNotEqualF(_curDynamicStates.depthMinBounds, minBounds) || + math::isNotEqualF(_curDynamicStates.depthMaxBounds, maxBounds)) { + _curDynamicStates.depthMinBounds = minBounds; + _curDynamicStates.depthMaxBounds = maxBounds; + } +} + +void GLES3CommandEncoder::setStencilWriteMask(StencilFace face, uint32_t mask) { + auto update = [&](DynamicStencilStates &stencilState) { + if (stencilState.writeMask != mask) { + stencilState.writeMask = mask; + } + }; + if (hasFlag(face, StencilFace::FRONT)) update(_curDynamicStates.stencilStatesFront); + if (hasFlag(face, StencilFace::BACK)) update(_curDynamicStates.stencilStatesBack); +} + +void GLES3CommandEncoder::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) { + auto update = [&](DynamicStencilStates &stencilState) { + if ((stencilState.reference != ref) || + (stencilState.compareMask != mask)) { + stencilState.reference = ref; + stencilState.compareMask = mask; + } + }; + if (hasFlag(face, StencilFace::FRONT)) update(_curDynamicStates.stencilStatesFront); + if (hasFlag(face, StencilFace::BACK)) update(_curDynamicStates.stencilStatesBack); +} + +void GLES3CommandEncoder::bindDescriptorSets() { + auto setCount = _currentPipelineState->gpuPipelineLayout->setLayouts.size(); + for (uint32_t setID = 0; setID < setCount; ++setID) { + uint32_t dynamicIndex = 0; + uint32_t descriptorIndex = 0; + + const auto &dynamics = _dynamicOffsets[setID]; + auto *descriptorSet = _descriptorSets[setID]; + if (descriptorSet == nullptr) { + continue; + } + + auto *descriptorSetLayout = _currentPipelineState->gpuPipelineLayout->setLayouts[setID].get(); + for (auto &binding : descriptorSetLayout->bindings) { + auto offsetToPipelineLayout = _currentPipelineState->descriptorOffsets[setID]; + + const uint32_t *dynamicOffsetPtr = nullptr; + if (isDynamicBuffer(binding.type) && dynamicIndex + binding.count <= dynamics.size()) { + dynamicOffsetPtr = &dynamics[dynamicIndex]; + dynamicIndex += binding.count; + } + + auto *descriptorIndexBase = &_currentPipelineState->descriptorIndices[descriptorIndex + offsetToPipelineLayout]; + auto *descriptorBase = &descriptorSet->gpuDescriptors[descriptorIndex]; + + descriptorIndex += binding.count; + if (descriptorIndexBase->binding == INVALID_BINDING) { + continue; + } + for (uint32_t i = 0; i < binding.count; ++i) { + auto &descriptor = descriptorBase[i]; + auto &index = descriptorIndexBase[i]; + if (isBufferType(binding.type) && checkBuffer(descriptor)) { + uint32_t const offset = descriptor.gpuBufferView->offset + (dynamicOffsetPtr != nullptr ? dynamicOffsetPtr[i] : 0); + GL_CHECK(glBindBufferRange(getBufferTarget(binding.type), index.binding, + descriptor.gpuBufferView->gpuBuffer->glBuffer, + offset, + descriptor.gpuBufferView->range)); + } else if (checkTexture(descriptor)) { + GL_CHECK(glActiveTexture(GL_TEXTURE0 + index.unit)); + GL_CHECK(glBindTexture(descriptor.gpuTextureView->texture->glTarget, descriptor.gpuTextureView->texture->glTexture)); + GL_CHECK(glBindSampler(index.unit, descriptor.gpuSampler->glSampler)); + } + } + } + } +} + +void GLES3CommandEncoder::draw(const DrawInfo &drawInfo) { + if (_currentPipelineState == nullptr) { + return; + } + + const auto glPrimitive = _currentPipelineState->glPrimitive; + if (_currentIA == nullptr || _currentPipelineState == nullptr) { + return; + } + + bindDescriptorSets(); + + if (_currentIA->gpuIndexBuffer) { + if (drawInfo.indexCount > 0) { + uint8_t *offset = nullptr; + offset += static_cast(drawInfo.firstIndex * _currentIA->gpuIndexBuffer->stride); + if (drawInfo.instanceCount == 0) { + GL_CHECK(glDrawElements(glPrimitive, drawInfo.indexCount, _currentIA->glIndexType, offset)); + } else { + GL_CHECK(glDrawElementsInstanced(glPrimitive, drawInfo.indexCount, _currentIA->glIndexType, offset, drawInfo.instanceCount)); + } + } + } else if (drawInfo.vertexCount > 0) { + if (drawInfo.instanceCount == 0) { + GL_CHECK(glDrawArrays(glPrimitive, drawInfo.firstVertex, drawInfo.vertexCount)); + } else { + GL_CHECK(glDrawArraysInstanced(glPrimitive, drawInfo.firstVertex, drawInfo.vertexCount, drawInfo.instanceCount)); + } + } +} + +void GLES3CommandEncoder::drawIndirect() { + +} + +void GLES3CommandEncoder::drawIndexedIndirect() { + +} + +void GLES3CommandEncoder::dispatch(uint32_t x, uint32_t y, uint32_t z) { + if (_currentPipelineState == nullptr) { + return; + } + + bindDescriptorSets(); + GL_CHECK(glDispatchCompute(x, y, z)); +} + +void GLES3CommandEncoder::dispatchIndirect(GLESGPUBuffer *buffer, uint32_t offset) { + GL_CHECK(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->glBuffer)); + GL_CHECK(glDispatchComputeIndirect(offset)); + GL_CHECK(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0)); +} + +void GLES3CommandEncoder::updateBuffer(GLESGPUBuffer *buffer, const void *data, uint32_t size) { + cmdFuncGLES3UpdateBuffer(GLESDevice::getInstance(), buffer, data, 0, size, true, true); +} + +void GLES3CommandEncoder::begin(GLESGPUFence *waitFence) { +// if (waitFence != nullptr && waitFence->sync != nullptr) { +// glesWaitFence(GLESDevice::getInstance(), waitFence, UINT64_MAX, true); +// glesDestroyFence(GLESDevice::getInstance(), waitFence); +// } +} + +void GLES3CommandEncoder::end(GLESGPUFence *signalFence) { +// if (signalFence != nullptr) { +// glesCreateFence(GLESDevice::getInstance(), signalFence); +// } +} + +void GLES3CommandEncoder::attachContext(egl::Context *context, GLESGPUStateCache *cacheState) { + _context = context; + _cacheState = cacheState; +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.h b/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.h new file mode 100644 index 00000000000..decd4308f43 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3CommandEncoder.h @@ -0,0 +1,58 @@ +#pragma once + +#include "base/std/container/array.h" +#include "gfx-gles-common/common/GLESCommandEncoder.h" + +namespace cc::gfx { +struct GLESGPUFramebuffer; +struct GLESGPURenderPass; + +class GLES3CommandEncoder : public GLESCommandEncoder { +public: + GLES3CommandEncoder() = default; + ~GLES3CommandEncoder() override = default; + + static constexpr uint32_t MAX_SET = 4; + + void beginRenderPass(const PassBeginInfo &beginInfo) override; + void endRenderPass() override; + void nextSubPass() override; + void bindPipelineState(GLESGPUPipelineState *pso) override; + void bindDescriptorSet(uint32_t setID, const DescriptorBindInfo &bindInfo) override; + void bindInputAssembler(GLESGPUInputAssembler *ia) override; + void setViewport(const Viewport &vp) override; + void setScissor(const Rect &rect) override; + void setLineWidth(float width) override; + void setDepthBias(float constant, float clamp, float slope) override; + void setBlendConstants(const Color &constants) override; + void setDepthBound(float minBounds, float maxBounds) override; + void setStencilWriteMask(StencilFace face, uint32_t mask) override; + void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) override; + void draw(const DrawInfo &drawInfo) override; + void drawIndirect() override; + void drawIndexedIndirect() override; + void dispatch(uint32_t x, uint32_t y, uint32_t z) override; + void dispatchIndirect(GLESGPUBuffer *buffer, uint32_t offset) override; + void updateBuffer(GLESGPUBuffer *buffer, const void *data, uint32_t size) override; + void begin(GLESGPUFence *waitFence) override; + void end(GLESGPUFence *signalFence) override; + + // invoke only main thread. + void attachContext(egl::Context *context, GLESGPUStateCache *cacheState) override; +private: + void bindDescriptorSets(); + + egl::Context *_context = nullptr; + GLESGPUStateCache *_cacheState = nullptr; + + uint32_t _curSubPassIdx = 0; + GLESGPUInputAssembler *_currentIA = nullptr; + GLESGPUPipelineState *_currentPipelineState = nullptr; + GLESGPUFramebuffer *_currentFramebuffer = nullptr; + const GLESGPURenderPass *_currentRenderPass = nullptr; + DynamicStates _curDynamicStates; + + ccstd::array, MAX_SET> _dynamicOffsets; + ccstd::array _descriptorSets; +}; +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.cpp b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.cpp new file mode 100644 index 00000000000..bf67db9f82a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.cpp @@ -0,0 +1,1122 @@ +#include "GLES3Commands.h" +#include "base/StringUtil.h" +#include "gfx-gles-common/egl/Debug.h" +#include "gfx-gles-common/loader/gles3w.h" + +#include "gfx-gles-common/common/GLESDevice.h" +#include "gfx-gles-common/common/GLESPipelineState.h" + +namespace cc::gfx { + +#include "GLES3Types.inl" + + +namespace { +constexpr GLenum DFT_BUF_TARGET = GL_ARRAY_BUFFER; + +void uploadBufferData(GLESGPUBuffer *gpuBuffer, GLintptr offset, GLsizeiptr length, const void *buffer, bool useMap, bool sync) { + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, gpuBuffer->glBuffer)); + + if (!useMap) { + GL_CHECK(glBufferSubData(DFT_BUF_TARGET, offset, length, buffer)); + } else { + void *dst = nullptr; + const auto mapBits = sync ? GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT : + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + GL_CHECK(dst = glMapBufferRange(DFT_BUF_TARGET, offset, length, mapBits)); + if (!dst) { + GL_CHECK(glBufferSubData(DFT_BUF_TARGET, offset, length, buffer)); + return; + } + memcpy(dst, buffer, length); + GL_CHECK(glUnmapBuffer(DFT_BUF_TARGET)); + } + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, 0)); +} + +uint32_t roundUp(uint32_t numToRound, uint32_t multiple) { + return ((numToRound + multiple - 1) / multiple) * multiple; +} +} // namespace + +void cmdFuncGLES3CreateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer) { + if (hasAllFlags(BufferUsageBit::TRANSFER_SRC | BufferUsageBit::TRANSFER_DST, gpuBuffer->usage)) { + // Only use staging buffers when necessary, as they are typically not recommended on devices with unified memory architectures. + gpuBuffer->buffer = std::make_unique(gpuBuffer->size); + } else { + GL_CHECK(glGenBuffers(1, &gpuBuffer->glBuffer)); + gpuBuffer->glUsage = hasFlag(gpuBuffer->memUsage, MemoryUsageBit::HOST) ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW; + + uint32_t size = gpuBuffer->size; + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, gpuBuffer->glBuffer)); + GL_CHECK(glBufferData(DFT_BUF_TARGET, size, nullptr, gpuBuffer->glUsage)); + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, 0)); + } +} + +void cmdFuncGLES3DestroyBuffer(GLESDevice */*device*/, GLuint *bufferIDs, uint32_t count) { + if (bufferIDs != nullptr && count > 0) { + GL_CHECK(glDeleteBuffers(count, bufferIDs)); + } +} + +void cmdFuncGLES3ResizeBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer) { + if (gpuBuffer->glBuffer != 0) { + uint32_t size = gpuBuffer->size; + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, gpuBuffer->glBuffer)); + GL_CHECK(glBufferData(DFT_BUF_TARGET, size, nullptr, gpuBuffer->glUsage)); + GL_CHECK(glBindBuffer(DFT_BUF_TARGET, 0)); + } else { + gpuBuffer->buffer = std::make_unique(gpuBuffer->size); + } +} + +void cmdFuncGLES3UpdateBuffer(GLESDevice */*device*/, GLESGPUBuffer *gpuBuffer, const void *buffer, uint32_t offset, uint32_t size, bool useMap, bool sync) { + if (gpuBuffer->buffer) { + memcpy(gpuBuffer->buffer.get() + offset, buffer, size); + } else { + uploadBufferData(gpuBuffer, offset, size, buffer, useMap, sync); + } +} + +namespace { +void renderBufferStorage(GLESDevice */*device*/, GLESGPUTexture *gpuTexture) { + CC_ASSERT(gpuTexture->type == TextureType::TEX2D); + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, gpuTexture->glRenderbuffer)); + if (gpuTexture->glSamples > 1) { + GL_CHECK(glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, gpuTexture->glSamples, gpuTexture->glInternalFmt, gpuTexture->width, gpuTexture->height)); + } else { + GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, gpuTexture->glInternalFmt, gpuTexture->width, gpuTexture->height)); + } + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0)); +} + +void textureStorage(GLESDevice *device, GLESGPUTexture *gpuTexture) { + auto w = gpuTexture->width; + auto h = gpuTexture->height; + auto d = gpuTexture->type == TextureType::TEX2D_ARRAY ? gpuTexture->arrayLayer : gpuTexture->depth; + + switch (gpuTexture->type) { + case TextureType::CUBE: + CC_ASSERT(gpuTexture->glSamples <= 1); + gpuTexture->glTarget = GL_TEXTURE_CUBE_MAP; + GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, gpuTexture->glTexture)); + GL_CHECK(glTexStorage2D(GL_TEXTURE_CUBE_MAP, gpuTexture->mipLevel, gpuTexture->glInternalFmt, w, h)); + GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, 0)); + break; + case TextureType::TEX2D: + if (gpuTexture->glSamples > 1 && device->constantRegistry().minorVersion >= 1) { + gpuTexture->glTarget = GL_TEXTURE_2D_MULTISAMPLE; + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, gpuTexture->glTexture)); + GL_CHECK(glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, gpuTexture->glSamples, gpuTexture->glInternalFmt, w, h, GL_FALSE)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0)); + } else { + gpuTexture->glTarget = GL_TEXTURE_2D; + GL_CHECK(glBindTexture(GL_TEXTURE_2D, gpuTexture->glTexture)); + GL_CHECK(glTexStorage2D(GL_TEXTURE_2D, gpuTexture->mipLevel, gpuTexture->glInternalFmt, w, h)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0)); + } + break; + case TextureType::TEX3D: + CC_ASSERT(gpuTexture->glSamples <= 1); + gpuTexture->glTarget = GL_TEXTURE_3D; + GL_CHECK(glBindTexture(GL_TEXTURE_3D, gpuTexture->glTexture)); + GL_CHECK(glTexStorage3D(GL_TEXTURE_3D, gpuTexture->mipLevel, gpuTexture->glInternalFmt, w, h, d)); + GL_CHECK(glBindTexture(GL_TEXTURE_3D, 0)); + break; + case TextureType::TEX2D_ARRAY: + if (gpuTexture->glSamples > 1 && device->constantRegistry().minorVersion >= 1) { + gpuTexture->glTarget = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, gpuTexture->glTexture)); + GL_CHECK(glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, gpuTexture->glSamples, gpuTexture->glInternalFmt, w, h, d, GL_FALSE)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0)); + } else { + gpuTexture->glTarget = GL_TEXTURE_2D_ARRAY; + GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, gpuTexture->glTexture)); + GL_CHECK(glTexStorage3D(GL_TEXTURE_2D_ARRAY, gpuTexture->mipLevel, gpuTexture->glInternalFmt, w, h, d)); + GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, 0)); + } + break; + default: + break; + } +} + +bool useRenderBuffer(const GLESDevice *device, Format format, TextureUsage usage) { + return !device->isTextureExclusive(format) && + hasAllFlags(TextureUsage::COLOR_ATTACHMENT | TextureUsage::DEPTH_STENCIL_ATTACHMENT, usage); +} +} // namespace + +void cmdFuncGLES3CreateTexture(GLESDevice *device, GLESGPUTexture *gpuTexture) { + if (gpuTexture->swapchain != nullptr) { + return; + } + + gpuTexture->glInternalFmt = mapGLInternalFormat(gpuTexture->format); + gpuTexture->glFormat = mapGLFormat(gpuTexture->format); + gpuTexture->glType = formatToGLType(gpuTexture->format); + + bool const supportRenderBufferMS = device->constantRegistry().mMSRT > MSRTSupportLevel::NONE; + gpuTexture->useRenderBuffer = useRenderBuffer(device, gpuTexture->format, gpuTexture->usage) && + (gpuTexture->glSamples <= 1 || supportRenderBufferMS); + + if (gpuTexture->glSamples > 1) { + // Allocate render buffer when binding a framebuffer if the MSRT extension is not present. + if (gpuTexture->useRenderBuffer && + hasFlag(gpuTexture->flags, TextureFlagBit::LAZILY_ALLOCATED)) { + gpuTexture->memoryAllocated = false; + return; + } + } + + if (gpuTexture->glTexture != 0) { + return; + } + + if (gpuTexture->size == 0) { + return; + } + + if (gpuTexture->useRenderBuffer) { + GL_CHECK(glGenRenderbuffers(1, &gpuTexture->glRenderbuffer)); + renderBufferStorage(device, gpuTexture); + } else { + GL_CHECK(glGenTextures(1, &gpuTexture->glTexture)); + textureStorage(device, gpuTexture); + } +} + +void cmdFuncGLES3DestroyTexture(GLESDevice *device, GLuint *texIDs, uint32_t count) { + if (texIDs != nullptr && count > 0) { + GL_CHECK(glDeleteTextures(count, texIDs)); + } +} + +void cmdFuncGLES3DestroyRenderBuffer(GLESDevice *device, GLuint *renderbufferIDs, uint32_t count) { + if (renderbufferIDs != nullptr && count > 0) { + GL_CHECK(glDeleteRenderbuffers(count, renderbufferIDs)); + } +} + +void cmdFuncGLES3ResizeTexture(GLESDevice *device, GLESGPUTexture *gpuTexture) { + CC_ASSERT(!gpuTexture->immutable); + if (gpuTexture->size == 0) { + return; + } + + if (gpuTexture->useRenderBuffer) { + renderBufferStorage(device, gpuTexture); + } +} + +void cmdFuncGLES3UpdateProgramBinaryFormats(GLESDevice */*device*/, ccstd::vector &formats) { + GLint shaderBinaryFormats = 0; + GL_CHECK(glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &shaderBinaryFormats)); + + formats.resize(shaderBinaryFormats); + GL_CHECK(glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats.data())); +} + +void cmdFuncGLES3CreateShaderByBinary(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash) { + auto *pipelineCache = device->pipelineCache(); + if (pipelineCache == nullptr || gpuShader->hash == INVALID_SHADER_HASH) { + return; + } + + ccstd::hash_t hash = gpuShader->hash; + ccstd::hash_combine(hash, layoutHash); + + auto *item = pipelineCache->fetchBinary(gpuShader->name, hash); + if (item != nullptr) { + GL_CHECK(gpuShader->glProgram = glCreateProgram()); + GL_CHECK(glProgramBinary(gpuShader->glProgram, item->format, item->data.data(), item->data.size())); + } +} + +void cmdFuncGLES3CreateShaderBySource(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash) { + GLenum glShaderStage = 0; + ccstd::string shaderStageStr; + GLint status; + + for (size_t i = 0; i < gpuShader->stages.size(); ++i) { + GLESGPUShader::Stage &gpuStage = gpuShader->stages[i]; + + switch (gpuStage.type) { + case ShaderStageFlagBit::VERTEX: { + glShaderStage = GL_VERTEX_SHADER; + shaderStageStr = "Vertex Shader"; + break; + } + case ShaderStageFlagBit::FRAGMENT: { + glShaderStage = GL_FRAGMENT_SHADER; + shaderStageStr = "Fragment Shader"; + break; + } + case ShaderStageFlagBit::COMPUTE: { + glShaderStage = GL_COMPUTE_SHADER; + shaderStageStr = "Compute Shader"; + break; + } + default: { + CC_ABORT(); + return; + } + } + GL_CHECK(gpuStage.glShader = glCreateShader(glShaderStage)); + uint32_t const version = 300 + device->constantRegistry().minorVersion * 10; + ccstd::string const shaderSource = StringUtil::format("#version %u es\n", version) + gpuStage.source; + const char *source = shaderSource.c_str(); + GL_CHECK(glShaderSource(gpuStage.glShader, 1, (const GLchar **)&source, nullptr)); + GL_CHECK(glCompileShader(gpuStage.glShader)); + + GL_CHECK(glGetShaderiv(gpuStage.glShader, GL_COMPILE_STATUS, &status)); + if (status != GL_TRUE) { + GLint logSize = 0; + GL_CHECK(glGetShaderiv(gpuStage.glShader, GL_INFO_LOG_LENGTH, &logSize)); + + ++logSize; + auto *logs = static_cast(CC_MALLOC(logSize)); + GL_CHECK(glGetShaderInfoLog(gpuStage.glShader, logSize, nullptr, logs)); + + CC_LOG_ERROR("%s in %s compilation failed.", shaderStageStr.c_str(), gpuShader->name.c_str()); + CC_LOG_ERROR(logs); + CC_FREE(logs); + GL_CHECK(glDeleteShader(gpuStage.glShader)); + gpuStage.glShader = 0; + return; + } + } + + GL_CHECK(gpuShader->glProgram = glCreateProgram()); + + // link program + for (size_t i = 0; i < gpuShader->stages.size(); ++i) { + auto &gpuStage = gpuShader->stages[i]; + GL_CHECK(glAttachShader(gpuShader->glProgram, gpuStage.glShader)); + } + + GL_CHECK(glLinkProgram(gpuShader->glProgram)); + + // detach & delete immediately + for (size_t i = 0; i < gpuShader->stages.size(); ++i) { + auto &gpuStage = gpuShader->stages[i]; + if (gpuStage.glShader) { + GL_CHECK(glDetachShader(gpuShader->glProgram, gpuStage.glShader)); + GL_CHECK(glDeleteShader(gpuStage.glShader)); + gpuStage.glShader = 0; + } + } + + GL_CHECK(glGetProgramiv(gpuShader->glProgram, GL_LINK_STATUS, &status)); + if (status != 1) { + CC_LOG_ERROR("Failed to link Shader [%s].", gpuShader->name.c_str()); + GLint logSize = 0; + GL_CHECK(glGetProgramiv(gpuShader->glProgram, GL_INFO_LOG_LENGTH, &logSize)); + if (logSize) { + ++logSize; + auto *logs = static_cast(CC_MALLOC(logSize)); + GL_CHECK(glGetProgramInfoLog(gpuShader->glProgram, logSize, nullptr, logs)); + + CC_LOG_ERROR(logs); + CC_FREE(logs); + return; + } + } + + auto *cache = device->pipelineCache(); + if (cache != nullptr && gpuShader->hash != INVALID_SHADER_HASH) { + GLint binaryLength = 0; + GL_CHECK(glGetProgramiv(gpuShader->glProgram, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); + GLsizei length = 0; + auto *binary = ccnew GLESGPUProgramBinary(); + binary->name = gpuShader->name; + binary->hash = gpuShader->hash; + ccstd::hash_combine(binary->hash, layoutHash); + binary->data.resize(binaryLength); + GL_CHECK(glGetProgramBinary(gpuShader->glProgram, binaryLength, &length, &binary->format, binary->data.data())); + cache->addBinary(binary); + } +} + +void cmdFuncGLES3DestroyProgram(GLESDevice */*device*/, GLuint programID) { + if (programID != 0) { + GL_CHECK(glDeleteProgram(programID)); + } +} + +void cmdFuncGLES3CreateRenderPass(GLESDevice */*device*/, GLESGPURenderPass *gpuRenderPass) { + auto &subPasses = gpuRenderPass->subpasses; + auto &attachments = gpuRenderPass->colorAttachments; + auto &drawBuffers = gpuRenderPass->drawBuffers; + + gpuRenderPass->drawBuffers.resize(subPasses.size()); + gpuRenderPass->indices.resize(attachments.size(), INVALID_BINDING); + + for (uint32_t i = 0; i < subPasses.size(); ++i) { + auto &sub = subPasses[i]; + auto &drawBuffer = drawBuffers[i]; + + std::vector visited(gpuRenderPass->colorAttachments.size()); + for (auto &input : sub.inputs) { + visited[input] = true; + drawBuffer.emplace_back(gpuRenderPass->indices[input]); + } + + for (auto &color : sub.colors) { + auto &index = gpuRenderPass->indices[color]; + if (index == INVALID_BINDING) { + index = static_cast(gpuRenderPass->colors.size()); + gpuRenderPass->colors.emplace_back(color); + } + if (!visited[color]) { + drawBuffer.emplace_back(index); + } + } + + for (auto &resolve : sub.resolves) { + if (resolve == INVALID_BINDING) { + gpuRenderPass->resolves.emplace_back(resolve); + continue; + } + auto &index = gpuRenderPass->indices[resolve]; + if (index == INVALID_BINDING) { + index = static_cast(gpuRenderPass->resolves.size()); + gpuRenderPass->resolves.emplace_back(resolve); + } + } + + gpuRenderPass->depthStencil = sub.depthStencil; + gpuRenderPass->depthStencilResolve = sub.depthStencilResolve; + } +} + +void cmdFuncGLES3CreateInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler) { + if (gpuInputAssembler->gpuIndexBuffer) { + switch (gpuInputAssembler->gpuIndexBuffer->stride) { + case 1: gpuInputAssembler->glIndexType = GL_UNSIGNED_BYTE; break; + case 2: gpuInputAssembler->glIndexType = GL_UNSIGNED_SHORT; break; + case 4: gpuInputAssembler->glIndexType = GL_UNSIGNED_INT; break; + default: { + CC_LOG_ERROR("Illegal index buffer stride."); + } + } + } + + ccstd::vector streamOffsets(device->getCapabilities().maxVertexAttributes, 0U); + + gpuInputAssembler->glAttribs.resize(gpuInputAssembler->attributes.size()); + for (size_t i = 0; i < gpuInputAssembler->glAttribs.size(); ++i) { + GLESGPUAttribute &gpuAttribute = gpuInputAssembler->glAttribs[i]; + const Attribute &attrib = gpuInputAssembler->attributes[i]; + const auto *gpuVB = gpuInputAssembler->gpuVertexBuffers[attrib.stream].get(); + + gpuAttribute.name = attrib.name; + gpuAttribute.glType = formatToGLType(attrib.format); + gpuAttribute.size = GFX_FORMAT_INFOS[static_cast(attrib.format)].size; + gpuAttribute.count = GFX_FORMAT_INFOS[static_cast(attrib.format)].count; + gpuAttribute.componentCount = glComponentCount(gpuAttribute.glType); + gpuAttribute.isNormalized = attrib.isNormalized; + gpuAttribute.isInstanced = attrib.isInstanced; + gpuAttribute.offset = streamOffsets[attrib.stream]; + + if (gpuVB) { + gpuAttribute.offset += gpuVB->offset; + gpuAttribute.glBuffer = gpuVB->gpuBuffer->glBuffer; + gpuAttribute.stride = gpuVB->stride; + } + streamOffsets[attrib.stream] += gpuAttribute.size; + } +} + +void cmdFuncGLES3DestroyInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler) { +} + +namespace { +GLESGPUSwapchain *getSwapchainIfExists(const GLESGPUTextureViewList &textureViews, const uint32_t *indices, size_t count) { + GLESGPUSwapchain *swapchain{nullptr}; + if (indices) { + for (size_t i = 0; i < count; ++i) { + if (indices[i] == INVALID_BINDING) { + continue; + } + auto *colorTexture = textureViews[indices[i]]->texture.get(); + if (colorTexture->swapchain) { + swapchain = colorTexture->swapchain; + } + } + } + return swapchain; +} +GLbitfield getColorBufferMask(Format format) { + GLbitfield mask = 0U; + const FormatInfo &info = GFX_FORMAT_INFOS[toNumber(format)]; + if (info.hasDepth || info.hasStencil) { + if (info.hasDepth) mask |= GL_DEPTH_BUFFER_BIT; + if (info.hasStencil) mask |= GL_STENCIL_BUFFER_BIT; + } else { + mask = GL_COLOR_BUFFER_BIT; + } + return mask; +} +} // namespace + +void cmdFuncGLES3CreateFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex) { + const auto *renderPass = gpuFBO->gpuRenderPass.get(); + const auto &colors = renderPass->colors; + const auto &resolves = renderPass->resolves; + const auto &indices = renderPass->indices; + const auto depthStencil = renderPass->depthStencil; + const auto depthStencilResolve = renderPass->depthStencilResolve; + + auto framebuffer = FBOProxy(gpuFBO->framebuffer, contextIndex); + auto resolveFramebuffer = FBOProxy(gpuFBO->resolveFramebuffer, contextIndex); + + framebuffer.initialize(getSwapchainIfExists(gpuFBO->gpuColorViews, colors.data(), colors.size())); + resolveFramebuffer.initialize(getSwapchainIfExists(gpuFBO->gpuColorViews, resolves.data(), resolves.size())); + + auto supportLevel = device->constantRegistry().mMSRT; + /* + * LEVEL0 does ont support on-chip resolve + * LEVEL1 only support COLOR_ATTACHMENT0 + * LEVEL2 support COLOR_ATTACHMENT(i) + DEPTH_STENCIL + */ + uint32_t const supportCount = supportLevel > MSRTSupportLevel::LEVEL1 ? 255 : static_cast(supportLevel); + constexpr bool useDsResolve = true; + + uint32_t resolveColorIndex = 0; + for (uint32_t i = 0; i < colors.size(); ++i) { + const auto &attachmentIndex = colors[i]; + const auto &colorIndex = indices[attachmentIndex]; + const auto &resolveIndex = resolves.empty() ? INVALID_BINDING : resolves[attachmentIndex]; + + const auto &desc = renderPass->colorAttachments[attachmentIndex]; + const auto *view = gpuFBO->gpuColorViews[attachmentIndex].get(); + CC_ASSERT(view != nullptr); + + // need to resolve + if (view->texture->glSamples > 1 && resolveIndex != INVALID_BINDING) { + const auto &resolveDesc = renderPass->colorAttachments[resolveIndex]; + const auto *resolveView = gpuFBO->gpuColorViews[resolveIndex].get(); + CC_ASSERT(resolveView != nullptr); + bool const lazilyAllocated = hasFlag(view->texture->flags, TextureFlagBit::LAZILY_ALLOCATED); + + if (lazilyAllocated && // MS attachment should be memoryless + resolveView->texture->swapchain == nullptr && // not back buffer + i < supportCount) { // extension limit + framebuffer.bindColorMultiSample(resolveView, colorIndex, view->texture->glSamples, resolveDesc); + } else { + // implicit MS not supported, fallback to MS Renderbuffer + gpuFBO->colorBlitPairs.emplace_back(colorIndex, resolveColorIndex); + gpuFBO->needResolve = true; + framebuffer.bindColor(view, colorIndex, desc); + resolveFramebuffer.bindColor(resolveView, resolveColorIndex++, resolveDesc); + } + continue; + } + framebuffer.bindColor(view, colorIndex, desc); + } + + if (depthStencil != INVALID_BINDING) { + const auto &desc = renderPass->depthStencilAttachment; + const auto *view = gpuFBO->gpuDepthStencilView.get(); + CC_ASSERT(view != nullptr); + + if (view->texture->glSamples > 1 && depthStencilResolve != INVALID_BINDING) { + const auto &resolveDesc = renderPass->depthStencilResolveAttachment; + const auto *resolveView = gpuFBO->gpuDepthStencilResolveView.get(); + bool const lazilyAllocated = hasFlag(view->texture->flags, TextureFlagBit::LAZILY_ALLOCATED); + + if (lazilyAllocated && // MS attachment should be memoryless + resolveView->texture->swapchain == nullptr && // not back buffer + supportCount > 1 && // extension limit + useDsResolve) { // enable ds implicit resolve + framebuffer.bindDepthStencilMultiSample(resolveView, view->texture->glSamples, resolveDesc); + } else { + // implicit MS not supported, fallback to MS Renderbuffer + gpuFBO->dsResolveMask = getColorBufferMask(desc.format); + gpuFBO->needResolve = true; + framebuffer.bindDepthStencil(view, desc); + resolveFramebuffer.bindDepthStencil(resolveView, resolveDesc); + } + } else { + framebuffer.bindDepthStencil(view, desc); + } + } +} + +void cmdFuncGLES3DestroyFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex) { + +} + +void cmdFuncGLES3CreatePipelineState(GLESDevice */*device*/, GLESGPUPipelineState *gpuPso) { + gpuPso->glPrimitive = GLE_S3_PRIMITIVES[static_cast(gpuPso->primitive)]; + + const auto *pipelineLayout = gpuPso->gpuPipelineLayout.get(); + const auto *shader = gpuPso->gpuShader.get(); + const auto &descLayouts = pipelineLayout->setLayouts; + const auto glProgram = gpuPso->gpuShader->glProgram; + + // update vertex location + GLint attrMaxLength = 0; + GLint attrCount = 0; + GL_CHECK(glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrMaxLength)); + GL_CHECK(glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &attrCount)); + gpuPso->attributes.resize(attrCount); + for (GLint i = 0; i < attrCount; ++i) { + auto &gpuInput = gpuPso->attributes[i]; + ccstd::vector tmpName(attrMaxLength, 0); + GL_CHECK(glGetActiveAttrib(glProgram, i, attrMaxLength, &gpuInput.glLength, &gpuInput.glSize, &gpuInput.glType, tmpName.data())); + gpuInput.name = tmpName.data(); + gpuInput.glLoc = glGetAttribLocation(glProgram, tmpName.data()); + ccstd::hash_combine(gpuPso->inputHash, gpuInput.name); + ccstd::hash_combine(gpuPso->inputHash, gpuInput.glLength); + ccstd::hash_combine(gpuPso->inputHash, gpuInput.glSize); + ccstd::hash_combine(gpuPso->inputHash, gpuInput.glType); + ccstd::hash_combine(gpuPso->inputHash, gpuInput.glLoc); + } + + uint32_t offset = 0; + uint32_t blockOffset = 0; + uint32_t texUnit = 0; + ccstd::vector units; + + GL_CHECK(glUseProgram(glProgram)); + // update binding map + gpuPso->descriptorIndices.resize(pipelineLayout->descriptorCount, {INVALID_BINDING}); + for (uint32_t set = 0, descriptorIndex = 0; set < pipelineLayout->setLayouts.size(); ++set) { + const auto &setLayout = pipelineLayout->setLayouts[set]; + const auto &bindings = setLayout->bindings; + for (const auto &binding : bindings) { + if (binding.type == DescriptorType::UNIFORM_BUFFER || binding.type == DescriptorType::DYNAMIC_UNIFORM_BUFFER) { + for (const auto &block : shader->blocks) { + if (block.set != set || block.binding != binding.binding) { + continue; + } + + GLuint const blockIndex = glGetUniformBlockIndex(glProgram, block.name.c_str()); + if (blockIndex == GL_INVALID_INDEX) { + continue; + } + for (uint32_t j = 0; j < binding.count; ++j) { + GL_CHECK(glUniformBlockBinding(glProgram, blockIndex + j, blockOffset)); + auto &desc = gpuPso->descriptorIndices[descriptorIndex + j]; + desc.binding = blockOffset; + ++blockOffset; + } + } + } else if (binding.type == DescriptorType::STORAGE_BUFFER || binding.type == DescriptorType::DYNAMIC_STORAGE_BUFFER) { + for (const auto &buffer : shader->buffers) { + if (buffer.set != set || buffer.binding != binding.binding) { + continue; + } + + GLuint const bufferIndex = glGetProgramResourceIndex(glProgram, GL_SHADER_STORAGE_BLOCK, buffer.name.c_str()); + if (bufferIndex == GL_INVALID_INDEX) { + continue; + } + for (uint32_t j = 0; j < binding.count; ++j) { + auto &desc = gpuPso->descriptorIndices[descriptorIndex + j]; + GLint index = 0; + GLenum const prop = GL_BUFFER_BINDING; + glGetProgramResourceiv(glProgram, GL_SHADER_STORAGE_BLOCK, bufferIndex + j, 1, &prop, 1, nullptr, &index); + desc.binding = index; + } + } + } else if (binding.type == DescriptorType::SAMPLER_TEXTURE) { + for (const auto &texture : shader->samplerTextures) { + if (texture.set != set || texture.binding != binding.binding) { + continue; + } + + GLuint const loc = glGetUniformLocation(glProgram, texture.name.c_str()); + if (loc == GL_INVALID_INDEX) { + continue; + } + for (uint32_t j = 0; j < binding.count; ++j) { + auto &desc = gpuPso->descriptorIndices[descriptorIndex + j]; + desc.unit = texUnit++; + units.emplace_back(desc.unit); + } + if (!units.empty()) { + GL_CHECK(glUniform1iv(loc, static_cast(units.size()), units.data())); + units.clear(); + } + } + } else if (binding.type == DescriptorType::STORAGE_IMAGE) { + } + descriptorIndex += binding.count; + } + + gpuPso->descriptorOffsets.emplace_back(offset); + offset += setLayout->descriptorCount; + } + GL_CHECK(glUseProgram(0)); +} + +void cmdFuncGLES3DestroyPipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso) { + +} + +namespace { +void completeBarrier(GLESGPUGeneralBarrier *barrier) { + bool hasShaderWrites = false; + for (uint32_t mask = toNumber(barrier->prevAccesses); mask; mask = utils::clearLowestBit(mask)) { + switch (static_cast(utils::getLowestBit(mask))) { + case AccessFlagBit::COMPUTE_SHADER_WRITE: + case AccessFlagBit::VERTEX_SHADER_WRITE: + case AccessFlagBit::FRAGMENT_SHADER_WRITE: + case AccessFlagBit::COLOR_ATTACHMENT_WRITE: + case AccessFlagBit::DEPTH_STENCIL_ATTACHMENT_WRITE: + hasShaderWrites = true; + break; + default: + break; + } + } + + if (hasShaderWrites) { + for (uint32_t mask = toNumber(barrier->nextAccesses); mask; mask = utils::clearLowestBit(mask)) { + switch (static_cast(utils::getLowestBit(mask))) { + case AccessFlagBit::INDIRECT_BUFFER: + barrier->glBarriers |= GL_COMMAND_BARRIER_BIT; + break; + case AccessFlagBit::INDEX_BUFFER: + barrier->glBarriers |= GL_ELEMENT_ARRAY_BARRIER_BIT; + break; + case AccessFlagBit::VERTEX_BUFFER: + barrier->glBarriers |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; + break; + case AccessFlagBit::COMPUTE_SHADER_READ_UNIFORM_BUFFER: + case AccessFlagBit::VERTEX_SHADER_READ_UNIFORM_BUFFER: + case AccessFlagBit::FRAGMENT_SHADER_READ_UNIFORM_BUFFER: + barrier->glBarriersByRegion |= GL_UNIFORM_BARRIER_BIT; + break; + case AccessFlagBit::COMPUTE_SHADER_READ_TEXTURE: + case AccessFlagBit::VERTEX_SHADER_READ_TEXTURE: + case AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE: + case AccessFlagBit::FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT: + case AccessFlagBit::FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT: + barrier->glBarriersByRegion |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; + barrier->glBarriersByRegion |= GL_TEXTURE_FETCH_BARRIER_BIT; + break; + case AccessFlagBit::COMPUTE_SHADER_READ_OTHER: + case AccessFlagBit::VERTEX_SHADER_READ_OTHER: + case AccessFlagBit::FRAGMENT_SHADER_READ_OTHER: + barrier->glBarriersByRegion |= GL_SHADER_STORAGE_BARRIER_BIT; + break; + case AccessFlagBit::COLOR_ATTACHMENT_READ: + case AccessFlagBit::DEPTH_STENCIL_ATTACHMENT_READ: + barrier->glBarriersByRegion |= GL_FRAMEBUFFER_BARRIER_BIT; + break; + case AccessFlagBit::TRANSFER_READ: + barrier->glBarriersByRegion |= GL_FRAMEBUFFER_BARRIER_BIT; + barrier->glBarriers |= GL_TEXTURE_UPDATE_BARRIER_BIT; + barrier->glBarriers |= GL_BUFFER_UPDATE_BARRIER_BIT; + barrier->glBarriers |= GL_PIXEL_BUFFER_BARRIER_BIT; + break; + case AccessFlagBit::COMPUTE_SHADER_WRITE: + case AccessFlagBit::VERTEX_SHADER_WRITE: + case AccessFlagBit::FRAGMENT_SHADER_WRITE: + barrier->glBarriersByRegion |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; + barrier->glBarriersByRegion |= GL_SHADER_STORAGE_BARRIER_BIT; + break; + case AccessFlagBit::COLOR_ATTACHMENT_WRITE: + case AccessFlagBit::DEPTH_STENCIL_ATTACHMENT_WRITE: + barrier->glBarriersByRegion |= GL_FRAMEBUFFER_BARRIER_BIT; + break; + case AccessFlagBit::TRANSFER_WRITE: + barrier->glBarriersByRegion |= GL_FRAMEBUFFER_BARRIER_BIT; + barrier->glBarriers |= GL_TEXTURE_UPDATE_BARRIER_BIT; + barrier->glBarriers |= GL_BUFFER_UPDATE_BARRIER_BIT; + barrier->glBarriers |= GL_PIXEL_BUFFER_BARRIER_BIT; + break; + case AccessFlagBit::HOST_PREINITIALIZED: + case AccessFlagBit::HOST_WRITE: + case AccessFlagBit::PRESENT: + default: + break; + } + } + } +} +} // namespace +void cmdFuncGLES3CreateGeneralBarrier(GLESDevice */*device*/, GLESGPUGeneralBarrier *barrier) { + completeBarrier(barrier); +} + +void cmdFuncGLES3CreateSampler(GLESDevice */*device*/, GLESGPUSampler *gpuSampler) { + if (gpuSampler->minFilter == Filter::LINEAR || gpuSampler->minFilter == Filter::ANISOTROPIC) { + if (gpuSampler->mipFilter == Filter::LINEAR || gpuSampler->mipFilter == Filter::ANISOTROPIC) { + gpuSampler->glMinFilter = GL_LINEAR_MIPMAP_LINEAR; + } else if (gpuSampler->mipFilter == Filter::POINT) { + gpuSampler->glMinFilter = GL_LINEAR_MIPMAP_NEAREST; + } else { + gpuSampler->glMinFilter = GL_LINEAR; + } + } else { + if (gpuSampler->mipFilter == Filter::LINEAR || gpuSampler->mipFilter == Filter::ANISOTROPIC) { + gpuSampler->glMinFilter = GL_NEAREST_MIPMAP_LINEAR; + } else if (gpuSampler->mipFilter == Filter::POINT) { + gpuSampler->glMinFilter = GL_NEAREST_MIPMAP_NEAREST; + } else { + gpuSampler->glMinFilter = GL_NEAREST; + } + } + + if (gpuSampler->magFilter == Filter::LINEAR || gpuSampler->magFilter == Filter::ANISOTROPIC) { + gpuSampler->glMagFilter = GL_LINEAR; + } else { + gpuSampler->glMagFilter = GL_NEAREST; + } + + gpuSampler->glWrapS = GLES3_WRAPS[toNumber(gpuSampler->addressU)]; + gpuSampler->glWrapT = GLES3_WRAPS[toNumber(gpuSampler->addressV)]; + gpuSampler->glWrapR = GLES3_WRAPS[toNumber(gpuSampler->addressW)]; + + GL_CHECK(glGenSamplers(1, &gpuSampler->glSampler)); + GL_CHECK(glSamplerParameteri(gpuSampler->glSampler, GL_TEXTURE_MIN_FILTER, gpuSampler->glMinFilter)); + GL_CHECK(glSamplerParameteri(gpuSampler->glSampler, GL_TEXTURE_MAG_FILTER, gpuSampler->glMagFilter)); + GL_CHECK(glSamplerParameteri(gpuSampler->glSampler, GL_TEXTURE_WRAP_S, gpuSampler->glWrapS)); + GL_CHECK(glSamplerParameteri(gpuSampler->glSampler, GL_TEXTURE_WRAP_T, gpuSampler->glWrapT)); + GL_CHECK(glSamplerParameteri(gpuSampler->glSampler, GL_TEXTURE_WRAP_R, gpuSampler->glWrapR)); + GL_CHECK(glSamplerParameterf(gpuSampler->glSampler, GL_TEXTURE_MIN_LOD, static_cast(gpuSampler->minLod))); + GL_CHECK(glSamplerParameterf(gpuSampler->glSampler, GL_TEXTURE_MAX_LOD, static_cast(gpuSampler->maxLod))); +} + +void cmdFuncGLES3DestroySampler(GLESDevice */*device*/, GLESGPUSampler *gpuSampler) { + if (gpuSampler->glSampler != 0) { + glDeleteSamplers(1, &gpuSampler->glSampler); + gpuSampler->glSampler = 0; + } +} + +namespace { +uint8_t *funcGLES3PixelBufferPick(GLESDevice *device, const uint8_t *buffer, Format format, uint32_t offset, Extent stride, Extent extent) { + const auto blockHeight = formatAlignment(format).second; + + const uint32_t bufferSize = formatSize(format, extent.width, extent.height, extent.depth); + const uint32_t rowStride = formatSize(format, stride.width, 1, 1); + const uint32_t sliceStride = formatSize(format, stride.width, stride.height, 1); + const uint32_t chunkSize = formatSize(format, extent.width, 1, 1); + +// uint8_t *stagingBuffer = device->getStagingBuffer(bufferSize); + auto *stagingBuffer = ccnew uint8_t[bufferSize]; + + uint32_t bufferOffset = 0; + uint32_t destOffset = 0; + + for (uint32_t i = 0; i < extent.depth; i++) { + bufferOffset = offset + sliceStride * i; + for (uint32_t j = 0; j < extent.height; j += blockHeight) { + memcpy(stagingBuffer + destOffset, buffer + bufferOffset, chunkSize); + destOffset += chunkSize; + bufferOffset += rowStride; + } + } + + return stagingBuffer; +} +} // namespace + +void cmdFuncGLES3CopyBuffersToTexture(GLESDevice *device, const uint8_t *const *buffers, GLESGPUTexture *gpuTexture, const BufferTextureCopy *regions, uint32_t count) { + if (gpuTexture->useRenderBuffer) return; + + bool const isCompressed = GFX_FORMAT_INFOS[static_cast(gpuTexture->format)].isCompressed; + uint32_t n = 0; + + const auto blockSize = formatAlignment(gpuTexture->format); + uint32_t destWidth = 0; + uint32_t destHeight = 0; + + Extent extent{}; + Offset offset{}; + Extent stride{}; + + GLenum target = GL_NONE; + for (size_t i = 0; i < count; ++i) { + const BufferTextureCopy ®ion = regions[i]; + uint32_t const mipLevel = region.texSubres.mipLevel; + + offset.x = region.texOffset.x == 0 ? 0 : utils::alignTo(region.texOffset.x, static_cast(blockSize.first)); + offset.y = region.texOffset.y == 0 ? 0 : utils::alignTo(region.texOffset.y, static_cast(blockSize.second)); + offset.z = region.texOffset.z; + + extent.width = utils::alignTo(region.texExtent.width, static_cast(blockSize.first)); + extent.height = utils::alignTo(region.texExtent.height, static_cast(blockSize.second)); + extent.depth = gpuTexture->type == TextureType::TEX3D ? region.texExtent.depth : 1; + + stride.width = region.buffStride > 0 ? region.buffStride : extent.width; + stride.height = region.buffTexHeight > 0 ? region.buffTexHeight : extent.height; + + destWidth = (region.texExtent.width + offset.x == (gpuTexture->width >> mipLevel)) ? region.texExtent.width : extent.width; + destHeight = (region.texExtent.height + offset.y == (gpuTexture->height >> mipLevel)) ? region.texExtent.height : extent.height; + + const uint8_t *buff; + if (gpuTexture->type == TextureType::TEX2D) { + if (stride.width == extent.width && stride.height == extent.height) { + buff = buffers[n++] + region.buffOffset; + } else { + buff = funcGLES3PixelBufferPick(device, buffers[n++], gpuTexture->format, region.buffOffset, stride, extent); + } + + target = hasFlag(gpuTexture->flags, TextureFlagBit::EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; + GL_CHECK(glBindTexture(target, gpuTexture->glTexture)); + if (isCompressed) { + auto memSize = static_cast(formatSize(gpuTexture->format, extent.width, extent.height, 1)); + GL_CHECK(glCompressedTexSubImage2D(target, mipLevel, offset.x, offset.y, destWidth, destHeight, gpuTexture->glFormat, memSize, (GLvoid *)buff)); + } + else { + GL_CHECK(glTexSubImage2D(target, mipLevel, offset.x, offset.y, destWidth, destHeight, gpuTexture->glFormat, gpuTexture->glType, (GLvoid *)buff)); + } + } else if (gpuTexture->type == TextureType::TEX3D) { + if (stride.width == extent.width && stride.height == extent.height) { + buff = buffers[n++] + region.buffOffset; + } else { + buff = funcGLES3PixelBufferPick(device, buffers[n++], gpuTexture->format, region.buffOffset, stride, extent); + } + + target = GL_TEXTURE_3D; + GL_CHECK(glBindTexture(target, gpuTexture->glTexture)); + if (isCompressed) { + auto memSize = static_cast(formatSize(gpuTexture->format, extent.width, extent.height, extent.depth)); + GL_CHECK(glCompressedTexSubImage3D(target, mipLevel, offset.x, offset.y, offset.z, destWidth, destHeight, extent.depth, gpuTexture->glFormat, memSize, (GLvoid *)buff)); + } else { + GL_CHECK(glTexSubImage3D(target, mipLevel, offset.x, offset.y, offset.z, destWidth, destHeight, extent.depth, gpuTexture->glFormat, gpuTexture->glType, (GLvoid *)buff)); + } + } else if (gpuTexture->type == TextureType::CUBE) { + target = GL_TEXTURE_CUBE_MAP; + GL_CHECK(glBindTexture(target, gpuTexture->glTexture)); + uint32_t const faceCount = region.texSubres.baseArrayLayer + region.texSubres.layerCount; + for (uint32_t f = region.texSubres.baseArrayLayer; f < faceCount; ++f) { + if (stride.width == extent.width && stride.height == extent.height) { + buff = buffers[n++] + region.buffOffset; + } else { + buff = funcGLES3PixelBufferPick(device, buffers[n++], gpuTexture->format, region.buffOffset, stride, extent); + } + const auto faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + f; + if (isCompressed) { + auto memSize = static_cast(formatSize(gpuTexture->format, extent.width, extent.height, 1)); + GL_CHECK(glCompressedTexSubImage2D(faceTarget, mipLevel, offset.x, offset.y,destWidth, destHeight, gpuTexture->glFormat, memSize, (GLvoid *)buff)); + } else { + GL_CHECK(glTexSubImage2D(faceTarget, mipLevel, offset.x, offset.y, destWidth, destHeight, gpuTexture->glFormat, gpuTexture->glType, (GLvoid *)buff)); + } + } + } else if (gpuTexture->type == TextureType::TEX2D_ARRAY) { + target = GL_TEXTURE_2D_ARRAY; + GL_CHECK(glBindTexture(target, gpuTexture->glTexture)); + uint32_t const layerCount = region.texSubres.baseArrayLayer + region.texSubres.layerCount; + for (uint32_t z = region.texSubres.baseArrayLayer; z < layerCount; ++z) { + offset.z = static_cast(z); + + if (stride.width == extent.width && stride.height == extent.height) { + buff = buffers[n++] + region.buffOffset; + } else { + buff = funcGLES3PixelBufferPick(device, buffers[n++], gpuTexture->format, region.buffOffset, stride, extent); + } + + if (isCompressed) { + auto memSize = static_cast(formatSize(gpuTexture->format, extent.width, extent.height, 1)); + GL_CHECK(glCompressedTexSubImage3D(target, mipLevel, offset.x, offset.y, offset.z, destWidth, destHeight, extent.depth, gpuTexture->glFormat, memSize, (GLvoid *)buff)); + } else { + GL_CHECK(glTexSubImage3D(target, mipLevel, offset.x, offset.y, offset.z, destWidth, destHeight, extent.depth, gpuTexture->glFormat, gpuTexture->glType, (GLvoid *)buff)); + } + } + } else { + return; + } + } + + if (!isCompressed && hasFlag(gpuTexture->flags, TextureFlagBit::GEN_MIPMAP)) { + GL_CHECK(glGenerateMipmap(target)); + } + GL_CHECK(glBindTexture(target, 0)); +} + +void cmdFuncGLES3CreateFence(GLESDevice * /*device*/, GLESGPUFence *gpuFence) { + gpuFence->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void cmdFuncGLES3DestroyFence(GLESDevice * /*device*/, GLESGPUFence *gpuFence) { + GL_CHECK(glDeleteSync(gpuFence->sync)); +} + +void cmdFuncGLES3WaitFence(GLESDevice * /*device*/, GLESGPUFence *gpuFence, uint64_t timeout, bool isClient) { + if (isClient) { + GL_CHECK(glClientWaitSync(gpuFence->sync, GL_SYNC_FLUSH_COMMANDS_BIT, timeout)); + } else { + GL_CHECK(glWaitSync(gpuFence->sync, 0, GL_TIMEOUT_IGNORED)); + } +} + +VAOProxy::VAOProxy(GLESGPUInputAssembler &object, uint32_t ctxId, uint32_t layoutHash) + : ia(object), handle(ia.vaoMap[layoutHash][ctxId]) { +} + +FBOProxy::FBOProxy(GLESGPUFramebufferObject &object, uint32_t ctxId) : fbo(object), handle(fbo.handle[ctxId]) { + updateHandle(); +} + +void FBOProxy::initialize(GLESGPUSwapchain *swc) { + fbo.swapchain = swc; +} + +void FBOProxy::bindColor(const GLESGPUTextureView *texture, uint32_t colorIndex, const ColorAttachment &attachment) { + bindColorMultiSample(texture, colorIndex, 1, attachment); +} + +void FBOProxy::bindColorMultiSample(const GLESGPUTextureView *texture, uint32_t colorIndex, GLint samples, const ColorAttachment &attachment) { + if (colorIndex >= fbo.colors.size()) { + fbo.colors.resize(colorIndex + 1); + } + bool const isDefaultFb = fbo.swapchain != nullptr; + + if (attachment.loadOp == LoadOp::DISCARD) { + fbo.loadInvalidates.emplace_back(isDefaultFb ? GL_COLOR : GL_COLOR_ATTACHMENT0 + colorIndex); + } + if (attachment.storeOp == StoreOp::DISCARD) { + fbo.storeInvalidates.emplace_back(isDefaultFb ? GL_COLOR : GL_COLOR_ATTACHMENT0 + colorIndex); + } + fbo.colors[colorIndex] = {texture, samples}; +} + +void FBOProxy::bindDepthStencil(const GLESGPUTextureView *texture, const DepthStencilAttachment &attachment) { + bindDepthStencilMultiSample(texture, 1, attachment); +} + +void FBOProxy::bindDepthStencilMultiSample(const GLESGPUTextureView *texture, GLint samples, const DepthStencilAttachment &attachment) { + const FormatInfo &info = GFX_FORMAT_INFOS[toNumber(texture->texture->format)]; + + bool const isDefaultFb = fbo.swapchain != nullptr; + bool const hasDepth = info.hasDepth; + bool const hasStencil = info.hasStencil; + + fbo.dsAttachment = hasDepth && hasStencil ? GL_DEPTH_STENCIL_ATTACHMENT : + hasDepth ? GL_DEPTH_ATTACHMENT : GL_STENCIL_ATTACHMENT; + + if (hasDepth) { + auto att = isDefaultFb ? GL_DEPTH : GL_DEPTH_ATTACHMENT; + if (attachment.depthLoadOp == LoadOp::DISCARD) { + fbo.loadInvalidates.emplace_back(att); + } + if (attachment.depthStoreOp == StoreOp::DISCARD) { + fbo.storeInvalidates.emplace_back(att); + } + } + if (hasStencil) { + auto att = isDefaultFb ? GL_STENCIL : GL_STENCIL_ATTACHMENT; + if (attachment.stencilLoadOp == LoadOp::DISCARD) { + fbo.loadInvalidates.emplace_back(att); + } + if (attachment.stencilStoreOp == StoreOp::DISCARD) { + fbo.storeInvalidates.emplace_back(att); + } + } + + fbo.depthStencil.first = texture; + fbo.depthStencil.second = samples; +} + +bool FBOProxy::isActive() const { + return fbo.swapchain != nullptr || (handle != 0); +} + +void FBOProxy::updateHandle() { + if (fbo.swapchain != nullptr || handle != 0) { + return; + } + + if (fbo.colors.empty() && fbo.dsAttachment == GL_NONE) { + return; + } + + GL_CHECK(glGenFramebuffers(1, &handle)); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle)); + + auto bindAttachment = [](GLenum attachment, GLint samples, const GLESGPUTextureView *view) { + auto *texture = view->texture.get(); + if (samples > 1) { + CC_ASSERT(texture->glTexture != 0); + GL_CHECK(glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, + attachment, + GL_TEXTURE_2D, + texture->glTexture, + view->baseLevel, + static_cast(samples))); + return; + } + + if (texture->useRenderBuffer) { + /* + * Renderbuffer is not allocated if using lazily allocated flag. + * If the attachment does not meet the implicit MS condition, renderbuffer should be allocated here. + */ + if (texture->glRenderbuffer == 0) { + GL_CHECK(glGenRenderbuffers(1, &texture->glRenderbuffer)); + renderBufferStorage(GLESDevice::getInstance(), texture); + } + GL_CHECK(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, texture->glRenderbuffer)); + } else { + GLenum target = GL_TEXTURE_2D; + if (texture->type == TextureType::CUBE && view->layerCount == 1) { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + view->baseLayer; + } + GL_CHECK(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, texture->glTexture, view->baseLevel)); + } + }; + + ccstd::vector drawBuffers(fbo.colors.size(), GL_NONE); + for (uint32_t i = 0; i < fbo.colors.size(); ++i) { + const auto &[view, samples] = fbo.colors[i]; + auto att = static_cast(GL_COLOR_ATTACHMENT0 + i); + drawBuffers[i] = att; + bindAttachment(att, samples, view); + } + + if (fbo.depthStencil.first != nullptr) { + const auto &[view, samples] = fbo.depthStencil; + bindAttachment(fbo.dsAttachment, samples, view); + } + + if (!drawBuffers.empty()) { + GL_CHECK(glDrawBuffers(drawBuffers.size(), drawBuffers.data())); + } + + GLenum status; + GL_CHECK(status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)); + if (status != GL_FRAMEBUFFER_COMPLETE) { + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + CC_LOG_ERROR("checkFramebufferStatus() - FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + CC_LOG_ERROR("checkFramebufferStatus() - FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + CC_LOG_ERROR("checkFramebufferStatus() - FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + CC_LOG_ERROR("checkFramebufferStatus() - FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + CC_LOG_ERROR("checkFramebufferStatus() - FRAMEBUFFER_UNSUPPORTED"); + break; + default: + CC_LOG_ERROR("checkFramebufferStatus() - %x", status); + break; + } + } +} + +void FBOProxy::processLoad(GLenum target) { + if (!fbo.loadInvalidates.empty()) { + GL_CHECK(glInvalidateFramebuffer(target, utils::toUint(fbo.loadInvalidates.size()), fbo.loadInvalidates.data())); + } +} + +void FBOProxy::processStore(GLenum target) { + if (!fbo.storeInvalidates.empty()) { + GL_CHECK(glInvalidateFramebuffer(target, utils::toUint(fbo.storeInvalidates.size()), fbo.storeInvalidates.data())); + } +} +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.h b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.h new file mode 100644 index 00000000000..cb3bf8b793e --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Commands.h @@ -0,0 +1,85 @@ +#pragma once + +#include "base/std/container/array.h" +#include "gfx-gles-common/common/GLESBase.h" +namespace cc::gfx { +class GLESDevice; +struct GLESGPUBuffer; +struct GLESGPUTexture; +struct GLESGPUTextureView; +struct GLESGPUShader; +struct GLESGPUPipelineState; +struct GLESGPUInputAssembler; +struct GLESGPUFramebuffer; +struct GLESGPUFramebufferObject; +struct GLESGPUSampler; +struct GLESGPUGeneralBarrier; +struct GLESGPURenderPass; +struct GLESGPUSwapchain; +struct GLESGPUFence; + +void cmdFuncGLES3UpdateFormatFeatures(GLESDevice *device, ccstd::array(Format::COUNT)> &formatFeatures); +void cmdFuncGLES3UpdateTextureExclusive(GLESDevice *device, ccstd::array(Format::COUNT)> &textureExclusive); +void cmdFuncGLES3UpdateFeatureAndCapabilities(GLESDevice *device, DeviceCaps &caps, GLESGPUConstantRegistry &constantRegistry, + ccstd::array(Feature::COUNT)> &features); + +void cmdFuncGLES3CreateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +void cmdFuncGLES3ResizeBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer); +void cmdFuncGLES3UpdateBuffer(GLESDevice *device, GLESGPUBuffer *gpuBuffer, const void *buffer, uint32_t offset, uint32_t size, bool useMap, bool sync); +void cmdFuncGLES3DestroyBuffer(GLESDevice *device, GLuint *bufferIDs, uint32_t count); + +void cmdFuncGLES3CreateTexture(GLESDevice *device, GLESGPUTexture *gpuTexture); +void cmdFuncGLES3ResizeTexture(GLESDevice *device, GLESGPUTexture *gpuTexture); +void cmdFuncGLES3DestroyTexture(GLESDevice *device, GLuint *texIDs, uint32_t count); +void cmdFuncGLES3DestroyRenderBuffer(GLESDevice *device, GLuint *renderbufferIDs, uint32_t count); + +void cmdFuncGLES3UpdateProgramBinaryFormats(GLESDevice *device, ccstd::vector &formats); +void cmdFuncGLES3CreateShaderByBinary(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +void cmdFuncGLES3CreateShaderBySource(GLESDevice *device, GLESGPUShader *gpuShader, uint32_t layoutHash); +void cmdFuncGLES3DestroyProgram(GLESDevice *device, GLuint programID); + +void cmdFuncGLES3CreatePipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso); +void cmdFuncGLES3DestroyPipelineState(GLESDevice *device, GLESGPUPipelineState *gpuPso); + +void cmdFuncGLES3CreateInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); +void cmdFuncGLES3DestroyInputAssembler(GLESDevice *device, GLESGPUInputAssembler *gpuInputAssembler); + +void cmdFuncGLES3CreateFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); +void cmdFuncGLES3DestroyFramebuffer(GLESDevice *device, GLESGPUFramebuffer *gpuFBO, uint32_t contextIndex); + +void cmdFuncGLES3CreateSampler(GLESDevice *device, GLESGPUSampler *gpuSampler); +void cmdFuncGLES3DestroySampler(GLESDevice *device, GLESGPUSampler *gpuSampler); + +void cmdFuncGLES3CreateFence(GLESDevice *device, GLESGPUFence *gpuFence); +void cmdFuncGLES3DestroyFence(GLESDevice *device, GLESGPUFence *gpuFence); +void cmdFuncGLES3WaitFence(GLESDevice *device, GLESGPUFence *gpuFence, uint64_t timeout, bool isClient); + +void cmdFuncGLES3CreateRenderPass(GLESDevice *device, GLESGPURenderPass *gpuRenderPass); + +void cmdFuncGLES3CreateGeneralBarrier(GLESDevice *device, GLESGPUGeneralBarrier *barrier); + +void cmdFuncGLES3CopyBuffersToTexture(GLESDevice *device, const uint8_t *const *buffers, GLESGPUTexture *gpuTexture, const BufferTextureCopy *regions, uint32_t count); + +struct FBOProxy { + FBOProxy(GLESGPUFramebufferObject &object, uint32_t ctxId); + void initialize(GLESGPUSwapchain *swc = nullptr); + void bindColor(const GLESGPUTextureView *texture, uint32_t colorIndex, const ColorAttachment &attachment); + void bindColorMultiSample(const GLESGPUTextureView *texture, uint32_t colorIndex, GLint samples, const ColorAttachment &attachment); + void bindDepthStencil(const GLESGPUTextureView *texture, const DepthStencilAttachment &attachment); + void bindDepthStencilMultiSample(const GLESGPUTextureView *texture, GLint samples, const DepthStencilAttachment &attachment); + bool isActive() const; + void updateHandle(); + void processLoad(GLenum target); + void processStore(GLenum target); + + GLESGPUFramebufferObject &fbo; + GLuint &handle; +}; + +struct VAOProxy { + VAOProxy(GLESGPUInputAssembler &object, uint32_t ctxId, uint32_t layoutHash); + + GLESGPUInputAssembler &ia; + GLuint &handle; +}; +} // namespace cc::gfx diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3Features.cpp b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Features.cpp new file mode 100644 index 00000000000..54b5f59305a --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Features.cpp @@ -0,0 +1,316 @@ +#include "GLES3Commands.h" +#include "gfx-gles-common/loader/gles2w.h" +#include "gfx-gles-common/loader/gles3w.h" +#include "gfx-gles-common/common/GLESDevice.h" + +namespace cc::gfx { +#define ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP 1 + +void cmdFuncGLES3UpdateFormatFeatures(GLESDevice *device, ccstd::array(Format::COUNT)> &formatFeatures) { + FormatFeature tempFeature = {}; + + // builtin + tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R8)] = tempFeature; + formatFeatures[toNumber(Format::RG8)] = tempFeature; + formatFeatures[toNumber(Format::RGB8)] = tempFeature; + formatFeatures[toNumber(Format::RGBA8)] = tempFeature; + + tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE; + + formatFeatures[toNumber(Format::R8SN)] = tempFeature; + formatFeatures[toNumber(Format::RG8SN)] = tempFeature; + formatFeatures[toNumber(Format::RGB8SN)] = tempFeature; + formatFeatures[toNumber(Format::RGBA8SN)] = tempFeature; + formatFeatures[toNumber(Format::R5G6B5)] = tempFeature; + formatFeatures[toNumber(Format::RGBA4)] = tempFeature; + formatFeatures[toNumber(Format::RGB5A1)] = tempFeature; + formatFeatures[toNumber(Format::RGB10A2)] = tempFeature; + + formatFeatures[toNumber(Format::SRGB8)] = tempFeature; + formatFeatures[toNumber(Format::SRGB8_A8)] = tempFeature; + + formatFeatures[toNumber(Format::R11G11B10F)] = tempFeature; + formatFeatures[toNumber(Format::RGB9E5)] = tempFeature; + + formatFeatures[toNumber(Format::DEPTH)] = tempFeature; + formatFeatures[toNumber(Format::DEPTH_STENCIL)] = tempFeature; + + tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R16F)] = tempFeature; + formatFeatures[toNumber(Format::RG16F)] = tempFeature; + formatFeatures[toNumber(Format::RGB16F)] = tempFeature; + formatFeatures[toNumber(Format::RGBA16F)] = tempFeature; + + tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R32F)] = tempFeature; + formatFeatures[toNumber(Format::RG32F)] = tempFeature; + formatFeatures[toNumber(Format::RGB32F)] = tempFeature; + formatFeatures[toNumber(Format::RGBA32F)] = tempFeature; + + formatFeatures[toNumber(Format::RGB10A2UI)] = FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE; + + tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE; + + formatFeatures[toNumber(Format::R8I)] = tempFeature; + formatFeatures[toNumber(Format::R8UI)] = tempFeature; + formatFeatures[toNumber(Format::R16I)] = tempFeature; + formatFeatures[toNumber(Format::R16UI)] = tempFeature; + formatFeatures[toNumber(Format::R32I)] = tempFeature; + formatFeatures[toNumber(Format::R32UI)] = tempFeature; + + formatFeatures[toNumber(Format::RG8I)] = tempFeature; + formatFeatures[toNumber(Format::RG8UI)] = tempFeature; + formatFeatures[toNumber(Format::RG16I)] = tempFeature; + formatFeatures[toNumber(Format::RG16UI)] = tempFeature; + formatFeatures[toNumber(Format::RG32I)] = tempFeature; + formatFeatures[toNumber(Format::RG32UI)] = tempFeature; + + formatFeatures[toNumber(Format::RGB8I)] = tempFeature; + formatFeatures[toNumber(Format::RGB8UI)] = tempFeature; + formatFeatures[toNumber(Format::RGB16I)] = tempFeature; + formatFeatures[toNumber(Format::RGB16UI)] = tempFeature; + formatFeatures[toNumber(Format::RGB32I)] = tempFeature; + formatFeatures[toNumber(Format::RGB32UI)] = tempFeature; + + formatFeatures[toNumber(Format::RGBA8I)] = tempFeature; + formatFeatures[toNumber(Format::RGBA8UI)] = tempFeature; + formatFeatures[toNumber(Format::RGBA16I)] = tempFeature; + formatFeatures[toNumber(Format::RGBA16UI)] = tempFeature; + formatFeatures[toNumber(Format::RGBA32I)] = tempFeature; + formatFeatures[toNumber(Format::RGBA32UI)] = tempFeature; + + if (device->checkExtension("color_buffer_float")) { + formatFeatures[toNumber(Format::R32F)] |= FormatFeature::RENDER_TARGET; + formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::RENDER_TARGET; + formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::RENDER_TARGET; + } + + if (device->checkExtension("texture_float_linear")) { + formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::R32F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::LINEAR_FILTER; + } + + if (device->checkExtension("texture_half_float_linear")) { + formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::R16F)] |= FormatFeature::LINEAR_FILTER; + formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::LINEAR_FILTER; + } + + const FormatFeature compressedFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::LINEAR_FILTER; + + if (device->checkExtension("compressed_ETC1")) { + formatFeatures[toNumber(Format::ETC_RGB8)] = compressedFeature; + } + + formatFeatures[toNumber(Format::ETC2_RGB8)] = compressedFeature; + formatFeatures[toNumber(Format::ETC2_RGBA8)] = compressedFeature; + formatFeatures[toNumber(Format::ETC2_SRGB8)] = compressedFeature; + formatFeatures[toNumber(Format::ETC2_SRGB8_A8)] = compressedFeature; + formatFeatures[toNumber(Format::ETC2_RGB8_A1)] = compressedFeature; + formatFeatures[toNumber(Format::ETC2_SRGB8_A1)] = compressedFeature; + + if (device->checkExtension("texture_compression_pvrtc")) { + formatFeatures[toNumber(Format::PVRTC_RGB2)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGBA2)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGB4)] |= compressedFeature; + formatFeatures[toNumber(Format::PVRTC_RGBA4)] |= compressedFeature; + } + + if (device->checkExtension("texture_compression_astc")) { + formatFeatures[toNumber(Format::ASTC_RGBA_4X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_5X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_5X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_6X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_6X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_8X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_10X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_12X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_RGBA_12X12)] |= compressedFeature; + + formatFeatures[toNumber(Format::ASTC_SRGBA_4X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_5X4)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_5X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_6X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_6X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_8X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X5)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X6)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X8)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_10X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_12X10)] |= compressedFeature; + formatFeatures[toNumber(Format::ASTC_SRGBA_12X12)] |= compressedFeature; + } +} + +void cmdFuncGLES3UpdateTextureExclusive(GLESDevice *device, ccstd::array(Format::COUNT)> &textureExclusive) { + textureExclusive.fill(true); + + textureExclusive[toNumber(Format::R8)] = false; + textureExclusive[toNumber(Format::RG8)] = false; + textureExclusive[toNumber(Format::RGB8)] = false; + textureExclusive[toNumber(Format::R5G6B5)] = false; + textureExclusive[toNumber(Format::RGBA4)] = false; + + textureExclusive[toNumber(Format::RGB5A1)] = false; + textureExclusive[toNumber(Format::RGBA8)] = false; + textureExclusive[toNumber(Format::RGB10A2)] = false; + textureExclusive[toNumber(Format::RGB10A2UI)] = false; + textureExclusive[toNumber(Format::SRGB8_A8)] = false; + + textureExclusive[toNumber(Format::R8I)] = false; + textureExclusive[toNumber(Format::R8UI)] = false; + textureExclusive[toNumber(Format::R16I)] = false; + textureExclusive[toNumber(Format::R16UI)] = false; + textureExclusive[toNumber(Format::R32I)] = false; + textureExclusive[toNumber(Format::R32UI)] = false; + + textureExclusive[toNumber(Format::RG8I)] = false; + textureExclusive[toNumber(Format::RG8UI)] = false; + textureExclusive[toNumber(Format::RG16I)] = false; + textureExclusive[toNumber(Format::RG16UI)] = false; + textureExclusive[toNumber(Format::RG32I)] = false; + textureExclusive[toNumber(Format::RG32UI)] = false; + + textureExclusive[toNumber(Format::RGBA8I)] = false; + textureExclusive[toNumber(Format::RGBA8UI)] = false; + textureExclusive[toNumber(Format::RGBA16I)] = false; + textureExclusive[toNumber(Format::RGBA16UI)] = false; + textureExclusive[toNumber(Format::RGBA32I)] = false; + textureExclusive[toNumber(Format::RGBA32UI)] = false; + + textureExclusive[toNumber(Format::DEPTH)] = false; + textureExclusive[toNumber(Format::DEPTH_STENCIL)] = false; + + if (device->checkExtension("render_snorm")) { + // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_render_snorm.txt + // For 16, see https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_norm16.txt + textureExclusive[toNumber(Format::R8SN)] = false; + textureExclusive[toNumber(Format::RG8SN)] = false; + textureExclusive[toNumber(Format::RGB8SN)] = false; + textureExclusive[toNumber(Format::RGBA8SN)] = false; + } + + if (device->checkExtension("color_buffer_float")) { + textureExclusive[toNumber(Format::R32F)] = false; + textureExclusive[toNumber(Format::RG32F)] = false; + textureExclusive[toNumber(Format::RGBA32F)] = false; + } + if (device->checkExtension("color_buffer_half_float")) { + textureExclusive[toNumber(Format::R16F)] = false; + textureExclusive[toNumber(Format::RG16F)] = false; + textureExclusive[toNumber(Format::RGB16F)] = false; + textureExclusive[toNumber(Format::RGBA16F)] = false; + } +} + +void cmdFuncGLES3UpdateFeatureAndCapabilities(GLESDevice *device, DeviceCaps &caps, GLESGPUConstantRegistry &constantRegistry, ccstd::array(Feature::COUNT)> &features) { + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, reinterpret_cast(&caps.maxVertexAttributes)); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, reinterpret_cast(&caps.maxVertexUniformVectors)); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, reinterpret_cast(&caps.maxFragmentUniformVectors)); + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, reinterpret_cast(&caps.maxUniformBufferBindings)); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, reinterpret_cast(&caps.maxUniformBlockSize)); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, reinterpret_cast(&caps.maxColorRenderTargets)); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, reinterpret_cast(&caps.maxTextureUnits)); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, reinterpret_cast(&caps.maxVertexTextureUnits)); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, reinterpret_cast(&caps.maxTextureSize)); + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, reinterpret_cast(&caps.maxCubeMapTextureSize)); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast(&caps.uboOffsetAlignment)); + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, reinterpret_cast(&caps.maxArrayTextureLayers)); + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, reinterpret_cast(&caps.max3DTextureSize)); + + if (constantRegistry.minorVersion > 0) { + glGetIntegerv(GL_MAX_IMAGE_UNITS, reinterpret_cast(&caps.maxImageUnits)); + glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, reinterpret_cast(&caps.maxShaderStorageBlockSize)); + glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, reinterpret_cast(&caps.maxShaderStorageBufferBindings)); + glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, reinterpret_cast(&caps.maxComputeSharedMemorySize)); + glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, reinterpret_cast(&caps.maxComputeWorkGroupInvocations)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, reinterpret_cast(&caps.maxComputeWorkGroupSize.x)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, reinterpret_cast(&caps.maxComputeWorkGroupSize.y)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, reinterpret_cast(&caps.maxComputeWorkGroupSize.z)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, reinterpret_cast(&caps.maxComputeWorkGroupCount.x)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, reinterpret_cast(&caps.maxComputeWorkGroupCount.y)); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, reinterpret_cast(&caps.maxComputeWorkGroupCount.z)); + } + + if (device->checkExtension("occlusion_query_boolean")) { + caps.supportQuery = true; + } + + features[toNumber(Feature::INSTANCED_ARRAYS)] = true; + features[toNumber(Feature::MULTIPLE_RENDER_TARGETS)] = true; + features[toNumber(Feature::BLEND_MINMAX)] = true; + features[toNumber(Feature::ELEMENT_INDEX_UINT)] = true; + features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = false; + features[toNumber(Feature::COMPUTE_SHADER)] = constantRegistry.minorVersion > 0; + + ccstd::string fbfLevelStr = "NONE"; + if (device->checkExtension("framebuffer_fetch")) { + if (device->checkExtension(CC_TOSTR(GL_EXT_shader_framebuffer_fetch_non_coherent))) { + constantRegistry.mFBF = FBFSupportLevel::NON_COHERENT_EXT; + features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true; + fbfLevelStr = "NON_COHERENT_EXT"; + } else if (device->checkExtension(CC_TOSTR(GL_QCOM_shader_framebuffer_fetch_noncoherent))) { + constantRegistry.mFBF = FBFSupportLevel::NON_COHERENT_QCOM; + features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true; + fbfLevelStr = "NON_COHERENT_QCOM"; + } else { + // we only care about EXT_shader_framebuffer_fetch, the ARM version does not support MRT + constantRegistry.mFBF = FBFSupportLevel::COHERENT; + fbfLevelStr = "COHERENT"; + } + + features[toNumber(Feature::INPUT_ATTACHMENT_BENEFIT)] = true; + features[toNumber(Feature::SUBPASS_COLOR_INPUT)] = true; + } + + if (device->checkExtension(CC_TOSTR(ARM_shader_framebuffer_fetch_depth_stencil))) { + features[toNumber(Feature::SUBPASS_DEPTH_STENCIL_INPUT)] = true; + fbfLevelStr += "_DEPTH_STENCIL"; + } + constantRegistry.fbfLevelStr = fbfLevelStr; + + ccstd::string msaaLevelStr = "NONE"; +#if CC_PLATFORM != CC_PLATFORM_WINDOWS || ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP + if (device->checkExtension("multisampled_render_to_texture")) { + if (device->checkExtension("multisampled_render_to_texture2")) { + constantRegistry.mMSRT = MSRTSupportLevel::LEVEL2; + msaaLevelStr = "MSRT2"; + } else { + constantRegistry.mMSRT = MSRTSupportLevel::LEVEL1; + msaaLevelStr = "MSRT1"; + } + } +#endif + constantRegistry.msaaLevelStr = msaaLevelStr; + + features[toNumber(Feature::MULTI_SAMPLE_RESOLVE_DEPTH_STENCIL)] = true; + + // compressed feature + constantRegistry.compressedFmts = "etc2 "; + if (device->getFormatFeatures(Format::ETC_RGB8) != FormatFeature::NONE) { + constantRegistry.compressedFmts += "etc1 "; + } + + if (device->getFormatFeatures(Format::PVRTC_RGB2) != FormatFeature::NONE) { + constantRegistry.compressedFmts += "pvrtc "; + } + + if (device->getFormatFeatures(Format::ASTC_RGBA_4X4) != FormatFeature::NONE) { + constantRegistry.compressedFmts += "astc "; + } +} +} // namespace cc::gfx \ No newline at end of file diff --git a/native/cocos/renderer/gfx-gles-common/gles3/GLES3Types.inl b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Types.inl new file mode 100644 index 00000000000..e77e5c4aae8 --- /dev/null +++ b/native/cocos/renderer/gfx-gles-common/gles3/GLES3Types.inl @@ -0,0 +1,518 @@ +namespace { +GLenum mapGLInternalFormat(Format format) { + switch (format) { + case Format::A8: return GL_ALPHA; + case Format::L8: return GL_LUMINANCE; + case Format::LA8: return GL_LUMINANCE_ALPHA; + + case Format::R8: return GL_R8; + case Format::R8SN: return GL_R8_SNORM; + case Format::R8UI: return GL_R8UI; + case Format::R8I: return GL_R8I; + case Format::RG8: return GL_RG8; + case Format::RG8SN: return GL_RG8_SNORM; + case Format::RG8UI: return GL_RG8UI; + case Format::RG8I: return GL_RG8I; + case Format::RGB8: return GL_RGB8; + case Format::RGB8SN: return GL_RGB8_SNORM; + case Format::RGB8UI: return GL_RGB8UI; + case Format::RGB8I: return GL_RGB8I; + case Format::SRGB8: return GL_SRGB_EXT; + case Format::RGBA8: return GL_RGBA8; + case Format::RGBA8SN: return GL_RGBA8_SNORM; + case Format::RGBA8UI: return GL_RGBA8UI; + case Format::RGBA8I: return GL_RGBA8I; + case Format::SRGB8_A8: return GL_SRGB_ALPHA_EXT; + case Format::R16I: return GL_R16I; + case Format::R16UI: return GL_R16UI; + case Format::R16F: return GL_R16F; + case Format::RG16I: return GL_RG16I; + case Format::RG16UI: return GL_RG16UI; + case Format::RG16F: return GL_RG16F; + case Format::RGB16I: return GL_RGB16I; + case Format::RGB16UI: return GL_RGB16UI; + case Format::RGB16F: return GL_RGB16F; + case Format::RGBA16I: return GL_RGBA16I; + case Format::RGBA16UI: return GL_RGBA16UI; + case Format::RGBA16F: return GL_RGBA16F; + case Format::R32I: return GL_R32I; + case Format::R32UI: return GL_R32UI; + case Format::R32F: return GL_R32F; + case Format::RG32I: return GL_RG32I; + case Format::RG32UI: return GL_RG32UI; + case Format::RG32F: return GL_RG32F; + case Format::RGB32I: return GL_RGB32I; + case Format::RGB32UI: return GL_RGB32UI; + case Format::RGB32F: return GL_RGB32F; + case Format::RGBA32I: return GL_RGBA32I; + case Format::RGBA32UI: return GL_RGBA32UI; + case Format::RGBA32F: return GL_RGBA32F; + case Format::R5G6B5: return GL_RGB565; + case Format::RGB5A1: return GL_RGB5_A1; + case Format::RGB9E5: return GL_RGB9_E5; + case Format::RGBA4: return GL_RGBA4; + case Format::RGB10A2: return GL_RGB10_A2; + case Format::RGB10A2UI: return GL_RGB10_A2UI; + case Format::R11G11B10F: return GL_R11F_G11F_B10F; + case Format::DEPTH: return GL_DEPTH_COMPONENT32F; + case Format::DEPTH_STENCIL: return GL_DEPTH24_STENCIL8; + + case Format::BC1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case Format::BC1_ALPHA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case Format::BC1_SRGB: return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + case Format::BC1_SRGB_ALPHA: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + + case Format::BC2: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case Format::BC2_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + + case Format::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case Format::BC3_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + + case Format::ETC_RGB8: return GL_ETC1_RGB8_OES; + case Format::ETC2_RGB8: return GL_COMPRESSED_RGB8_ETC2; + case Format::ETC2_SRGB8: return GL_COMPRESSED_SRGB8_ETC2; + case Format::ETC2_RGB8_A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case Format::ETC2_SRGB8_A1: return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case Format::ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC; + case Format::ETC2_SRGB8_A8: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + + case Format::EAC_R11: return GL_COMPRESSED_R11_EAC; + case Format::EAC_R11SN: return GL_COMPRESSED_SIGNED_R11_EAC; + case Format::EAC_RG11: return GL_COMPRESSED_RG11_EAC; + case Format::EAC_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; + + case Format::PVRTC_RGB2: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGBA2: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGB4: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + case Format::PVRTC_RGBA4: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + + case Format::ASTC_RGBA_4X4: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + case Format::ASTC_RGBA_5X4: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR; + case Format::ASTC_RGBA_5X5: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR; + case Format::ASTC_RGBA_6X5: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR; + case Format::ASTC_RGBA_6X6: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR; + case Format::ASTC_RGBA_8X5: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR; + case Format::ASTC_RGBA_8X6: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR; + case Format::ASTC_RGBA_8X8: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + case Format::ASTC_RGBA_10X5: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + case Format::ASTC_RGBA_10X6: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + case Format::ASTC_RGBA_10X8: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + case Format::ASTC_RGBA_10X10: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + case Format::ASTC_RGBA_12X10: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + case Format::ASTC_RGBA_12X12: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + + case Format::ASTC_SRGBA_4X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; + case Format::ASTC_SRGBA_5X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; + case Format::ASTC_SRGBA_5X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; + case Format::ASTC_SRGBA_6X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; + case Format::ASTC_SRGBA_6X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; + case Format::ASTC_SRGBA_8X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; + case Format::ASTC_SRGBA_8X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + case Format::ASTC_SRGBA_8X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + case Format::ASTC_SRGBA_10X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + case Format::ASTC_SRGBA_10X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + case Format::ASTC_SRGBA_10X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + case Format::ASTC_SRGBA_10X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + case Format::ASTC_SRGBA_12X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + case Format::ASTC_SRGBA_12X12: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; + + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +GLenum mapGLFormat(Format format) { + switch (format) { + case Format::A8: return GL_ALPHA; + case Format::L8: return GL_LUMINANCE; + case Format::LA8: return GL_LUMINANCE_ALPHA; + + case Format::R8: + case Format::R8SN: + case Format::R16F: + case Format::R32F: return GL_RED; + case Format::RG8: + case Format::RG8SN: + case Format::RG16F: + case Format::RG32F: return GL_RG; + case Format::RGB8: + case Format::RGB8SN: + case Format::RGB16F: + case Format::RGB32F: + case Format::R11G11B10F: + case Format::R5G6B5: + case Format::RGB9E5: + case Format::SRGB8: return GL_RGB; + case Format::RGBA8: + case Format::RGBA8SN: + case Format::RGBA16F: + case Format::RGBA32F: + case Format::RGBA4: + case Format::RGB5A1: + case Format::RGB10A2: + case Format::SRGB8_A8: return GL_RGBA; + + case Format::R8UI: + case Format::R8I: + case Format::R16UI: + case Format::R16I: + case Format::R32UI: + case Format::R32I: return GL_RED_INTEGER; + case Format::RG8UI: + case Format::RG8I: + case Format::RG16UI: + case Format::RG16I: + case Format::RG32UI: + case Format::RG32I: return GL_RG_INTEGER; + case Format::RGB8UI: + case Format::RGB8I: + case Format::RGB16UI: + case Format::RGB16I: + case Format::RGB32UI: + case Format::RGB32I: return GL_RGB_INTEGER; + case Format::RGBA8UI: + case Format::RGBA8I: + case Format::RGBA16UI: + case Format::RGBA16I: + case Format::RGBA32UI: + case Format::RGBA32I: + case Format::RGB10A2UI: return GL_RGBA_INTEGER; + + case Format::DEPTH: return GL_DEPTH_COMPONENT; + case Format::DEPTH_STENCIL: return GL_DEPTH_STENCIL; + + case Format::BC1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case Format::BC1_ALPHA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case Format::BC1_SRGB: return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + case Format::BC1_SRGB_ALPHA: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + case Format::BC2: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case Format::BC2_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + case Format::BC3: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + case Format::BC3_SRGB: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + + case Format::ETC_RGB8: return GL_ETC1_RGB8_OES; + case Format::ETC2_RGB8: return GL_COMPRESSED_RGB8_ETC2; + case Format::ETC2_SRGB8: return GL_COMPRESSED_SRGB8_ETC2; + case Format::ETC2_RGB8_A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case Format::ETC2_SRGB8_A1: return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case Format::ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC; + case Format::ETC2_SRGB8_A8: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + + case Format::EAC_R11: return GL_COMPRESSED_R11_EAC; + case Format::EAC_R11SN: return GL_COMPRESSED_SIGNED_R11_EAC; + case Format::EAC_RG11: return GL_COMPRESSED_RG11_EAC; + case Format::EAC_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; + + case Format::PVRTC_RGB2: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGBA2: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + case Format::PVRTC_RGB4: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + case Format::PVRTC_RGBA4: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + + case Format::ASTC_RGBA_4X4: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + case Format::ASTC_RGBA_5X4: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR; + case Format::ASTC_RGBA_5X5: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR; + case Format::ASTC_RGBA_6X5: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR; + case Format::ASTC_RGBA_6X6: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR; + case Format::ASTC_RGBA_8X5: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR; + case Format::ASTC_RGBA_8X6: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR; + case Format::ASTC_RGBA_8X8: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + case Format::ASTC_RGBA_10X5: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + case Format::ASTC_RGBA_10X6: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + case Format::ASTC_RGBA_10X8: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + case Format::ASTC_RGBA_10X10: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + case Format::ASTC_RGBA_12X10: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + case Format::ASTC_RGBA_12X12: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + + case Format::ASTC_SRGBA_4X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; + case Format::ASTC_SRGBA_5X4: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; + case Format::ASTC_SRGBA_5X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; + case Format::ASTC_SRGBA_6X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; + case Format::ASTC_SRGBA_6X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; + case Format::ASTC_SRGBA_8X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; + case Format::ASTC_SRGBA_8X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + case Format::ASTC_SRGBA_8X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + case Format::ASTC_SRGBA_10X5: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + case Format::ASTC_SRGBA_10X6: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + case Format::ASTC_SRGBA_10X8: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + case Format::ASTC_SRGBA_10X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + case Format::ASTC_SRGBA_12X10: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + case Format::ASTC_SRGBA_12X12: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; + + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +GLenum mapGLType(Type type) { + switch (type) { + case Type::BOOL: return GL_BOOL; + case Type::BOOL2: return GL_BOOL_VEC2; + case Type::BOOL3: return GL_BOOL_VEC3; + case Type::BOOL4: return GL_BOOL_VEC4; + case Type::INT: return GL_INT; + case Type::INT2: return GL_INT_VEC2; + case Type::INT3: return GL_INT_VEC3; + case Type::INT4: return GL_INT_VEC4; + case Type::UINT: return GL_UNSIGNED_INT; + case Type::FLOAT: return GL_FLOAT; + case Type::FLOAT2: return GL_FLOAT_VEC2; + case Type::FLOAT3: return GL_FLOAT_VEC3; + case Type::FLOAT4: return GL_FLOAT_VEC4; + case Type::MAT2: return GL_FLOAT_MAT2; + case Type::MAT2X3: return GL_FLOAT_MAT2x3; + case Type::MAT2X4: return GL_FLOAT_MAT2x4; + case Type::MAT3X2: return GL_FLOAT_MAT3x2; + case Type::MAT3: return GL_FLOAT_MAT3; + case Type::MAT3X4: return GL_FLOAT_MAT3x4; + case Type::MAT4X2: return GL_FLOAT_MAT4x2; + case Type::MAT4X3: return GL_FLOAT_MAT4x3; + case Type::MAT4: return GL_FLOAT_MAT4; + case Type::SAMPLER2D: return GL_SAMPLER_2D; + case Type::SAMPLER2D_ARRAY: return GL_SAMPLER_2D_ARRAY; + case Type::SAMPLER3D: return GL_SAMPLER_3D; + case Type::SAMPLER_CUBE: return GL_SAMPLER_CUBE; + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +Type mapType(GLenum glType) { + switch (glType) { + case GL_BOOL: return Type::BOOL; + case GL_BOOL_VEC2: return Type::BOOL2; + case GL_BOOL_VEC3: return Type::BOOL3; + case GL_BOOL_VEC4: return Type::BOOL4; + case GL_INT: return Type::INT; + case GL_INT_VEC2: return Type::INT2; + case GL_INT_VEC3: return Type::INT3; + case GL_INT_VEC4: return Type::INT4; + case GL_UNSIGNED_INT: return Type::UINT; + case GL_UNSIGNED_INT_VEC2: return Type::UINT2; + case GL_UNSIGNED_INT_VEC3: return Type::UINT3; + case GL_UNSIGNED_INT_VEC4: return Type::UINT4; + case GL_FLOAT: return Type::FLOAT; + case GL_FLOAT_VEC2: return Type::FLOAT2; + case GL_FLOAT_VEC3: return Type::FLOAT3; + case GL_FLOAT_VEC4: return Type::FLOAT4; + case GL_FLOAT_MAT2: return Type::MAT2; + case GL_FLOAT_MAT2x3: return Type::MAT2X3; + case GL_FLOAT_MAT2x4: return Type::MAT2X4; + case GL_FLOAT_MAT3x2: return Type::MAT3X2; + case GL_FLOAT_MAT3: return Type::MAT3; + case GL_FLOAT_MAT3x4: return Type::MAT3X4; + case GL_FLOAT_MAT4x2: return Type::MAT4X2; + case GL_FLOAT_MAT4x3: return Type::MAT4X3; + case GL_FLOAT_MAT4: return Type::MAT4; + case GL_SAMPLER_2D: return Type::SAMPLER2D; + case GL_SAMPLER_2D_ARRAY: return Type::SAMPLER2D_ARRAY; + case GL_SAMPLER_3D: return Type::SAMPLER3D; + case GL_SAMPLER_CUBE: return Type::SAMPLER_CUBE; + default: { + CC_ABORT(); + return Type::UNKNOWN; + } + } +} + +GLenum formatToGLType(Format format) { + switch (format) { + case Format::R8: return GL_UNSIGNED_BYTE; + case Format::R8SN: return GL_BYTE; + case Format::R8UI: return GL_UNSIGNED_BYTE; + case Format::R8I: return GL_BYTE; + case Format::R16F: return GL_HALF_FLOAT; + case Format::R16UI: return GL_UNSIGNED_SHORT; + case Format::R16I: return GL_SHORT; + case Format::R32F: return GL_FLOAT; + case Format::R32UI: return GL_UNSIGNED_INT; + case Format::R32I: return GL_INT; + + case Format::RG8: return GL_UNSIGNED_BYTE; + case Format::RG8SN: return GL_BYTE; + case Format::RG8UI: return GL_UNSIGNED_BYTE; + case Format::RG8I: return GL_BYTE; + case Format::RG16F: return GL_HALF_FLOAT; + case Format::RG16UI: return GL_UNSIGNED_SHORT; + case Format::RG16I: return GL_SHORT; + case Format::RG32F: return GL_FLOAT; + case Format::RG32UI: return GL_UNSIGNED_INT; + case Format::RG32I: return GL_INT; + + case Format::RGB8: + case Format::SRGB8: return GL_UNSIGNED_BYTE; + case Format::RGB8SN: return GL_BYTE; + case Format::RGB8UI: return GL_UNSIGNED_BYTE; + case Format::RGB8I: return GL_BYTE; + case Format::RGB16F: return GL_HALF_FLOAT; + case Format::RGB16UI: return GL_UNSIGNED_SHORT; + case Format::RGB16I: return GL_SHORT; + case Format::RGB32F: return GL_FLOAT; + case Format::RGB32UI: return GL_UNSIGNED_INT; + case Format::RGB32I: return GL_INT; + + case Format::RGBA8: + case Format::SRGB8_A8: return GL_UNSIGNED_BYTE; + case Format::RGBA8SN: return GL_BYTE; + case Format::RGBA8UI: return GL_UNSIGNED_BYTE; + case Format::RGBA8I: return GL_BYTE; + case Format::RGBA16F: return GL_HALF_FLOAT; + case Format::RGBA16UI: return GL_UNSIGNED_SHORT; + case Format::RGBA16I: return GL_SHORT; + case Format::RGBA32F: return GL_FLOAT; + case Format::RGBA32UI: return GL_UNSIGNED_INT; + case Format::RGBA32I: return GL_INT; + + case Format::R5G6B5: return GL_UNSIGNED_SHORT_5_6_5; + case Format::R11G11B10F: return GL_UNSIGNED_INT_10F_11F_11F_REV; + case Format::RGB5A1: return GL_UNSIGNED_SHORT_5_5_5_1; + case Format::RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; + case Format::RGB10A2: + case Format::RGB10A2UI: return GL_UNSIGNED_INT_2_10_10_10_REV; + case Format::RGB9E5: return GL_UNSIGNED_INT_5_9_9_9_REV; + + case Format::DEPTH: return GL_FLOAT; + case Format::DEPTH_STENCIL: return GL_UNSIGNED_INT_24_8; + + case Format::BC1: + case Format::BC1_SRGB: + case Format::BC2: + case Format::BC2_SRGB: + case Format::BC3: + case Format::BC3_SRGB: + case Format::BC4: return GL_UNSIGNED_BYTE; + case Format::BC4_SNORM: return GL_BYTE; + case Format::BC5: return GL_UNSIGNED_BYTE; + case Format::BC5_SNORM: return GL_BYTE; + case Format::BC6H_SF16: + case Format::BC6H_UF16: return GL_FLOAT; + case Format::BC7: + case Format::BC7_SRGB: + + case Format::ETC_RGB8: + case Format::ETC2_RGBA8: + case Format::ETC2_RGB8: + case Format::ETC2_SRGB8: + case Format::ETC2_RGB8_A1: + case Format::ETC2_SRGB8_A1: + case Format::EAC_R11: return GL_UNSIGNED_BYTE; + case Format::EAC_R11SN: return GL_BYTE; + case Format::EAC_RG11: return GL_UNSIGNED_BYTE; + case Format::EAC_RG11SN: return GL_BYTE; + + case Format::PVRTC_RGB2: + case Format::PVRTC_RGBA2: + case Format::PVRTC_RGB4: + case Format::PVRTC_RGBA4: + case Format::PVRTC2_2BPP: + case Format::PVRTC2_4BPP: + + case Format::ASTC_RGBA_4X4: + case Format::ASTC_RGBA_5X4: + case Format::ASTC_RGBA_5X5: + case Format::ASTC_RGBA_6X5: + case Format::ASTC_RGBA_6X6: + case Format::ASTC_RGBA_8X5: + case Format::ASTC_RGBA_8X6: + case Format::ASTC_RGBA_8X8: + case Format::ASTC_RGBA_10X5: + case Format::ASTC_RGBA_10X6: + case Format::ASTC_RGBA_10X8: + case Format::ASTC_RGBA_10X10: + case Format::ASTC_RGBA_12X10: + case Format::ASTC_RGBA_12X12: + case Format::ASTC_SRGBA_4X4: + case Format::ASTC_SRGBA_5X4: + case Format::ASTC_SRGBA_5X5: + case Format::ASTC_SRGBA_6X5: + case Format::ASTC_SRGBA_6X6: + case Format::ASTC_SRGBA_8X5: + case Format::ASTC_SRGBA_8X6: + case Format::ASTC_SRGBA_8X8: + case Format::ASTC_SRGBA_10X5: + case Format::ASTC_SRGBA_10X6: + case Format::ASTC_SRGBA_10X8: + case Format::ASTC_SRGBA_10X10: + case Format::ASTC_SRGBA_12X10: + case Format::ASTC_SRGBA_12X12: + return GL_UNSIGNED_BYTE; + + default: { + CC_ABORT(); + return GL_NONE; + } + } +} + +GLenum getTextureTarget(TextureType type) { + switch (type) { + case TextureType::TEX2D: return GL_TEXTURE_2D; + case TextureType::TEX2D_ARRAY: return GL_TEXTURE_2D_ARRAY; + case TextureType::TEX3D: return GL_TEXTURE_3D; + case TextureType::CUBE: return GL_TEXTURE_CUBE_MAP; + default: + CC_ABORT(); + return GL_NONE; + } +} + +uint32_t glComponentCount(GLenum glType) { + switch (glType) { + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: return 2; + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT3x4: return 3; + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + case GL_FLOAT_MAT4: return 4; + default: { + return 1; + } + } +} + +const GLenum GLES3_WRAPS[] = { + GL_REPEAT, + GL_MIRRORED_REPEAT, + GL_CLAMP_TO_EDGE, + GL_CLAMP_TO_EDGE, +}; + +const GLenum GLES3_FILTERS[] = { + GL_NONE, + GL_NEAREST, + GL_LINEAR, + GL_NONE, +}; + +const GLenum GLE_S3_PRIMITIVES[] = { + GL_POINTS, + GL_LINES, + GL_LINE_STRIP, + GL_LINE_LOOP, + GL_NONE, + GL_NONE, + GL_NONE, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN, + GL_NONE, + GL_NONE, + GL_NONE, + GL_NONE, +}; + +const GLenum GL_MEMORY_ACCESS[] = { + GL_READ_ONLY, + GL_WRITE_ONLY, + GL_READ_WRITE, +}; + +} // namespace \ No newline at end of file