You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
18 KiB
453 lines
18 KiB
/****************************************************************************
|
|
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
|
|
|
|
http://www.cocos.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include <thread>
|
|
#include "GLES3GPUObjects.h"
|
|
#include "base/StringUtil.h"
|
|
|
|
#if CC_SWAPPY_ENABLED
|
|
#include "swappy/swappyGL.h"
|
|
#endif
|
|
|
|
#define FORCE_DISABLE_VALIDATION 1
|
|
|
|
namespace cc {
|
|
namespace gfx {
|
|
|
|
#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION
|
|
constexpr uint32_t DISABLE_VALIDATION_ASSERTIONS = 1; // 0 for default behavior, otherwise assertions will be disabled
|
|
|
|
void GL_APIENTRY GLES3EGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) {
|
|
String sourceDesc;
|
|
switch (source) {
|
|
case GL_DEBUG_SOURCE_API_KHR: sourceDesc = "API"; break;
|
|
case GL_DEBUG_SOURCE_SHADER_COMPILER_KHR: sourceDesc = "SHADER_COMPILER"; break;
|
|
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR: sourceDesc = "WINDOW_SYSTEM"; break;
|
|
case GL_DEBUG_SOURCE_THIRD_PARTY_KHR: sourceDesc = "THIRD_PARTY"; break;
|
|
case GL_DEBUG_SOURCE_APPLICATION_KHR: sourceDesc = "APPLICATION"; break;
|
|
default: sourceDesc = "OTHER";
|
|
}
|
|
|
|
String typeDesc;
|
|
switch (type) {
|
|
case GL_DEBUG_TYPE_ERROR_KHR: typeDesc = "ERROR"; break;
|
|
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: typeDesc = "PEPRECATED_BEHAVIOR"; break;
|
|
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: typeDesc = "UNDEFINED_BEHAVIOR"; break;
|
|
case GL_DEBUG_TYPE_PERFORMANCE_KHR: typeDesc = "PERFORMANCE"; break;
|
|
case GL_DEBUG_TYPE_PORTABILITY_KHR: typeDesc = "PORTABILITY"; break;
|
|
case GL_DEBUG_TYPE_MARKER_KHR: typeDesc = "MARKER"; break;
|
|
case GL_DEBUG_TYPE_PUSH_GROUP_KHR: typeDesc = "PUSH_GROUP"; break;
|
|
case GL_DEBUG_TYPE_POP_GROUP_KHR: typeDesc = "POP_GROUP"; break;
|
|
default: typeDesc = "OTHER";
|
|
}
|
|
|
|
String severityDesc;
|
|
switch (severity) {
|
|
case GL_DEBUG_SEVERITY_HIGH_KHR: severityDesc = "HIGH"; break;
|
|
case GL_DEBUG_SEVERITY_MEDIUM_KHR: severityDesc = "MEDIUM"; break;
|
|
case GL_DEBUG_SEVERITY_LOW_KHR: severityDesc = "LOW"; break;
|
|
default: severityDesc = "NOTIFICATION";
|
|
}
|
|
|
|
String msg = StringUtil::format("source: %s, type: %s, severity: %s, message: %s",
|
|
sourceDesc.c_str(), typeDesc.c_str(), severityDesc.c_str(), message);
|
|
|
|
if (severity == GL_DEBUG_SEVERITY_HIGH_KHR) {
|
|
CC_LOG_ERROR(msg.c_str());
|
|
CC_ASSERT(DISABLE_VALIDATION_ASSERTIONS);
|
|
} else if (severity == GL_DEBUG_SEVERITY_MEDIUM_KHR) {
|
|
CC_LOG_WARNING(msg.c_str());
|
|
} else {
|
|
CC_LOG_DEBUG(msg.c_str());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bool GLES3GPUContext::initialize(GLES3GPUStateCache *stateCache, GLES3GPUConstantRegistry *constantRegistry) {
|
|
_stateCache = stateCache;
|
|
_constantRegistry = constantRegistry;
|
|
|
|
if (!gles3wInit()) {
|
|
return false;
|
|
}
|
|
|
|
EGL_CHECK(eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY));
|
|
|
|
if (eglDisplay == EGL_NO_DISPLAY) {
|
|
CC_LOG_ERROR("eglGetDisplay() - FAILED.");
|
|
return false;
|
|
}
|
|
|
|
EGLBoolean success{false};
|
|
EGL_CHECK(success = eglInitialize(eglDisplay, &eglMajorVersion, &eglMinorVersion));
|
|
|
|
if (!success) {
|
|
CC_LOG_ERROR("eglInitialize() - FAILED.");
|
|
return false;
|
|
}
|
|
|
|
EGL_CHECK(eglBindAPI(EGL_OPENGL_ES_API));
|
|
|
|
bool msaaEnabled{false};
|
|
bool qualityPreferred{false};
|
|
|
|
EGLint redSize{8};
|
|
EGLint greenSize{8};
|
|
EGLint blueSize{8};
|
|
EGLint alphaSize{8};
|
|
EGLint depthSize{24};
|
|
EGLint stencilSize{8};
|
|
EGLint sampleBufferSize{msaaEnabled ? EGL_DONT_CARE : 0};
|
|
EGLint sampleSize{msaaEnabled ? EGL_DONT_CARE : 0};
|
|
|
|
EGLint defaultAttribs[]{
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
|
|
EGL_BLUE_SIZE, blueSize,
|
|
EGL_GREEN_SIZE, greenSize,
|
|
EGL_RED_SIZE, redSize,
|
|
EGL_ALPHA_SIZE, alphaSize,
|
|
EGL_DEPTH_SIZE, depthSize,
|
|
EGL_STENCIL_SIZE, stencilSize,
|
|
EGL_SAMPLE_BUFFERS, sampleBufferSize,
|
|
EGL_SAMPLES, sampleSize,
|
|
EGL_NONE};
|
|
|
|
int numConfig{0};
|
|
ccstd::vector<EGLConfig> eglConfigs;
|
|
|
|
success = eglChooseConfig(eglDisplay, defaultAttribs, nullptr, 0, &numConfig);
|
|
if (success) {
|
|
eglConfigs.resize(numConfig);
|
|
} else {
|
|
CC_LOG_ERROR("Query GLES3 configuration failed.");
|
|
return false;
|
|
}
|
|
|
|
int count = numConfig;
|
|
EGL_CHECK(success = eglChooseConfig(eglDisplay, defaultAttribs, eglConfigs.data(), count, &numConfig));
|
|
if (!success || !numConfig) {
|
|
CC_LOG_ERROR("eglChooseConfig configuration failed.");
|
|
return false;
|
|
}
|
|
|
|
EGLint depth{0};
|
|
EGLint stencil{0};
|
|
EGLint sampleBuffers{0};
|
|
EGLint sampleCount{0};
|
|
EGLint params[8]{0};
|
|
uint64_t lastScore = qualityPreferred ? std::numeric_limits<uint64_t>::min() : std::numeric_limits<uint64_t>::max();
|
|
|
|
for (int i = 0; i < numConfig; i++) {
|
|
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]);
|
|
int bNonLinearDepth = 0;
|
|
|
|
/*------------------------------------------ANGLE's priority-----------------------------------------------*/
|
|
// Favor EGLConfigLists by RGB, then Depth, then Non-linear Depth, then Stencil, then Alpha
|
|
uint64_t currScore{0};
|
|
EGLint colorScore = std::abs(params[0] - redSize) + std::abs(params[1] - greenSize) + std::abs(params[2] - blueSize);
|
|
currScore |= static_cast<uint64_t>(std::min(std::max(params[6], 0), 15)) << 29;
|
|
currScore |= static_cast<uint64_t>(std::min(std::max(params[7], 0), 31)) << 24;
|
|
currScore |= static_cast<uint64_t>(std::min(colorScore, 127)) << 17;
|
|
currScore |= static_cast<uint64_t>(std::min(std::abs(params[4] - depthSize), 63)) << 11;
|
|
currScore |= static_cast<uint64_t>(std::min(std::abs(1 - bNonLinearDepth), 1)) << 10;
|
|
currScore |= static_cast<uint64_t>(std::min(std::abs(params[5] - stencilSize), 31)) << 6;
|
|
currScore |= static_cast<uint64_t>(std::min(std::abs(params[3] - alphaSize), 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 msaaLimit = (msaaEnabled ? (params[6] > 0 && params[7] > 0) : (params[6] == 0 && params[7] == 0));
|
|
// performancePreferred ? [>=] : [<] , egl configurations store in "ascending order"
|
|
bool 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;
|
|
}
|
|
}
|
|
|
|
CC_LOG_INFO("Setup EGLConfig: depth [%d] stencil [%d] sampleBuffer [%d] sampleCount [%d]", depth, stencil, sampleBuffers, sampleCount);
|
|
|
|
EGL_CHECK(_extensions = StringUtil::split(eglQueryString(eglDisplay, EGL_EXTENSIONS), " "));
|
|
|
|
bool hasKHRCreateCtx = checkExtension(CC_TOSTR(EGL_KHR_create_context));
|
|
if (hasKHRCreateCtx) {
|
|
eglAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
|
|
eglAttributes.push_back(3);
|
|
eglAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
|
|
eglAttributes.push_back(2);
|
|
#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 (int m = 2; m >= 0; --m) {
|
|
eglAttributes[3] = m;
|
|
eglDefaultContext = eglCreateContext(eglDisplay, eglConfig, nullptr, eglAttributes.data());
|
|
EGLint err = eglGetError(); // QNX throws egl errors on mismatch
|
|
if (eglDefaultContext && err == EGL_SUCCESS) {
|
|
_constantRegistry->glMinorVersion = m;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
eglAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
|
|
eglAttributes.push_back(3);
|
|
eglAttributes.push_back(EGL_NONE);
|
|
|
|
EGL_CHECK(eglDefaultContext = eglCreateContext(eglDisplay, eglConfig, nullptr, eglAttributes.data()));
|
|
}
|
|
|
|
if (!eglDefaultContext) {
|
|
CC_LOG_ERROR("Create EGL context failed.");
|
|
return false;
|
|
}
|
|
|
|
EGLint pbufferAttribs[]{
|
|
EGL_WIDTH, 1,
|
|
EGL_HEIGHT, 1,
|
|
EGL_NONE};
|
|
EGL_CHECK(eglDefaultSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs));
|
|
|
|
size_t threadID{std::hash<std::thread::id>{}(std::this_thread::get_id())};
|
|
_sharedContexts[threadID] = eglDefaultContext;
|
|
|
|
bindContext(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GLES3GPUContext::destroy() {
|
|
if (eglDisplay) {
|
|
makeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
}
|
|
|
|
if (eglDefaultSurface) {
|
|
EGL_CHECK(eglDestroySurface(eglDisplay, eglDefaultSurface));
|
|
eglDefaultSurface = EGL_NO_SURFACE;
|
|
}
|
|
|
|
for (auto pair : _sharedContexts) {
|
|
if (pair.second != eglDefaultContext) {
|
|
EGL_CHECK(eglDestroyContext(eglDisplay, pair.second));
|
|
}
|
|
}
|
|
_sharedContexts.clear();
|
|
|
|
if (eglDefaultContext) {
|
|
EGL_CHECK(eglDestroyContext(eglDisplay, eglDefaultContext));
|
|
eglDefaultContext = EGL_NO_SURFACE;
|
|
}
|
|
|
|
if (eglDisplay) {
|
|
EGL_CHECK(eglTerminate(eglDisplay));
|
|
eglDisplay = EGL_NO_DISPLAY;
|
|
}
|
|
|
|
gles3wExit();
|
|
}
|
|
|
|
void GLES3GPUContext::bindContext(bool bound) {
|
|
if (bound) {
|
|
makeCurrent(eglDefaultSurface, eglDefaultSurface, eglDefaultContext);
|
|
resetStates();
|
|
} else {
|
|
makeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT, false);
|
|
_eglCurrentDrawSurface = EGL_NO_SURFACE;
|
|
_eglCurrentReadSurface = EGL_NO_SURFACE;
|
|
}
|
|
}
|
|
|
|
void GLES3GPUContext::makeCurrent(const GLES3GPUSwapchain *drawSwapchain, const GLES3GPUSwapchain *readSwapchain) {
|
|
EGLSurface drawSurface = drawSwapchain ? drawSwapchain->eglSurface : _eglCurrentDrawSurface;
|
|
EGLSurface readSurface = readSwapchain ? readSwapchain->eglSurface : _eglCurrentReadSurface;
|
|
EGLContext prevContext = eglGetCurrentContext();
|
|
|
|
if (_eglCurrentDrawSurface == drawSurface && _eglCurrentReadSurface == readSurface && _eglCurrentContext == prevContext) {
|
|
return;
|
|
}
|
|
|
|
makeCurrent(drawSurface, readSurface, _eglCurrentContext);
|
|
|
|
if (prevContext != _eglCurrentContext) {
|
|
resetStates();
|
|
}
|
|
}
|
|
|
|
void GLES3GPUContext::present(const GLES3GPUSwapchain *swapchain) {
|
|
#if CC_SWAPPY_ENABLED
|
|
if (swapchain->swappyEnabled) {
|
|
// fallback to normal eglswap if swappy swap failed.
|
|
if (SwappyGL_swap(eglDisplay, swapchain->eglSurface)) {
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
// For an example, 2 windows changed to background will cause the eglSurface of both destroyed,
|
|
// and then make one of them foreground, and the other window's eglSurface will stays EGL_NO_SURFACE.
|
|
// But in GLES3Device::present it iterates all swapchains, and now the second window containing the invalid surface exists.
|
|
if (swapchain->eglSurface == EGL_NO_SURFACE) {
|
|
return;
|
|
}
|
|
if (_eglCurrentInterval != swapchain->eglSwapInterval) {
|
|
if (!eglSwapInterval(eglDisplay, swapchain->eglSwapInterval)) {
|
|
CC_LOG_ERROR("eglSwapInterval() - FAILED.");
|
|
}
|
|
|
|
_eglCurrentInterval = swapchain->eglSwapInterval;
|
|
}
|
|
makeCurrent(swapchain, swapchain);
|
|
EGL_CHECK(eglSwapBuffers(eglDisplay, swapchain->eglSurface));
|
|
}
|
|
|
|
EGLContext GLES3GPUContext::getSharedContext() {
|
|
size_t threadID{std::hash<std::thread::id>{}(std::this_thread::get_id())};
|
|
if (_sharedContexts.count(threadID)) return _sharedContexts[threadID];
|
|
|
|
EGLContext context = EGL_NO_CONTEXT;
|
|
EGL_CHECK(context = eglCreateContext(eglDisplay, eglConfig, eglDefaultContext, eglAttributes.data()));
|
|
|
|
if (!context) {
|
|
CC_LOG_ERROR("Create shared context failed.");
|
|
return EGL_NO_CONTEXT;
|
|
}
|
|
|
|
_sharedContexts[threadID] = context;
|
|
return context;
|
|
}
|
|
|
|
bool GLES3GPUContext::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface, EGLContext context, bool updateCache) {
|
|
bool succeeded;
|
|
EGL_CHECK(succeeded = eglMakeCurrent(eglDisplay, drawSurface, readSurface, context));
|
|
if (succeeded && updateCache) {
|
|
_eglCurrentDrawSurface = drawSurface;
|
|
_eglCurrentReadSurface = readSurface;
|
|
_eglCurrentContext = context;
|
|
}
|
|
return succeeded;
|
|
}
|
|
|
|
// NOLINTNEXTLINE(google-readability-function-size, readability-function-size)
|
|
void GLES3GPUContext::resetStates() const {
|
|
GL_CHECK(glPixelStorei(GL_PACK_ALIGNMENT, 1));
|
|
GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
|
GL_CHECK(glActiveTexture(GL_TEXTURE0));
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
GL_CHECK(glEnable(GL_SCISSOR_TEST));
|
|
GL_CHECK(glEnable(GL_CULL_FACE));
|
|
GL_CHECK(glCullFace(GL_BACK));
|
|
|
|
GL_CHECK(glFrontFace(GL_CCW));
|
|
|
|
GL_CHECK(glDisable(GL_SAMPLE_COVERAGE));
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
GL_CHECK(glEnable(GL_DEPTH_TEST));
|
|
GL_CHECK(glDepthMask(GL_TRUE));
|
|
GL_CHECK(glDepthFunc(GL_LESS));
|
|
|
|
GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 1, 0xffffffff));
|
|
GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP));
|
|
GL_CHECK(glStencilMaskSeparate(GL_FRONT, 0xffffffff));
|
|
GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 1, 0xffffffff));
|
|
GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP));
|
|
GL_CHECK(glStencilMaskSeparate(GL_BACK, 0xffffffff));
|
|
|
|
GL_CHECK(glDisable(GL_STENCIL_TEST));
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
GL_CHECK(glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE));
|
|
GL_CHECK(glDisable(GL_BLEND));
|
|
GL_CHECK(glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD));
|
|
GL_CHECK(glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO));
|
|
GL_CHECK(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
|
GL_CHECK(glBlendColor(0.0F, 0.0F, 0.0F, 0.0F));
|
|
|
|
GL_CHECK(glUseProgram(0));
|
|
|
|
GL_CHECK(glBindVertexArray(0));
|
|
|
|
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_COPY_READ_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_COPY_WRITE_BUFFER, 0));
|
|
|
|
if (_constantRegistry->glMinorVersion) {
|
|
GL_CHECK(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
|
|
GL_CHECK(glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0));
|
|
GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0));
|
|
}
|
|
|
|
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
|
|
GL_CHECK(glBindTexture(GL_TEXTURE_3D, 0));
|
|
GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, 0));
|
|
GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, 0));
|
|
|
|
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
|
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
|
|
|
|
#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION
|
|
GL_CHECK(glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR));
|
|
if (glDebugMessageControlKHR) {
|
|
GL_CHECK(glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE));
|
|
}
|
|
if (glDebugMessageCallbackKHR) {
|
|
GL_CHECK(glDebugMessageCallbackKHR(GLES3EGLDebugProc, NULL));
|
|
}
|
|
#endif
|
|
|
|
if (_constantRegistry->mFBF == FBFSupportLevel::NON_COHERENT_QCOM) {
|
|
GL_CHECK(glEnable(GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM));
|
|
}
|
|
|
|
_stateCache->reset();
|
|
|
|
_constantRegistry->currentBoundThreadID = std::hash<std::thread::id>{}(std::this_thread::get_id());
|
|
|
|
CC_LOG_DEBUG("EGL context bounded to thread %llx", _constantRegistry->currentBoundThreadID);
|
|
}
|
|
|
|
} // namespace gfx
|
|
} // namespace cc
|
|
|