mirror of https://github.com/axmolengine/axmol.git
265 lines
10 KiB
C++
265 lines
10 KiB
C++
/*
|
|
* cocos2d-x http://www.cocos2d-x.org
|
|
*
|
|
* Copyright (c) 2010-2014 - cocos2d-x community
|
|
* Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|
*
|
|
* Portions Copyright (c) Microsoft Open Technologies, Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and limitations under the License.
|
|
*/
|
|
|
|
#include "OpenGLES.h"
|
|
using namespace Platform;
|
|
using namespace Windows::UI::Xaml::Controls;
|
|
using namespace Windows::Foundation;
|
|
using namespace Windows::Foundation::Collections;
|
|
|
|
OpenGLES::OpenGLES() :
|
|
mEglDisplay(EGL_NO_DISPLAY),
|
|
mEglContext(EGL_NO_CONTEXT),
|
|
mEglConfig(nullptr)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
OpenGLES::~OpenGLES()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
void OpenGLES::Initialize()
|
|
{
|
|
const EGLint configAttributes[] =
|
|
{
|
|
EGL_RED_SIZE, 8,
|
|
EGL_GREEN_SIZE, 8,
|
|
EGL_BLUE_SIZE, 8,
|
|
EGL_ALPHA_SIZE, 8,
|
|
EGL_DEPTH_SIZE, 8,
|
|
EGL_STENCIL_SIZE, 8,
|
|
EGL_NONE
|
|
};
|
|
|
|
const EGLint contextAttributes[] =
|
|
{
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
EGL_NONE
|
|
};
|
|
|
|
const EGLint defaultDisplayAttributes[] =
|
|
{
|
|
// These are the default display attributes, used to request ANGLE's D3D11 renderer.
|
|
// eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
|
|
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
|
|
|
// #ifdef EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER
|
|
// // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
|
|
// // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
|
|
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
|
|
// #endif
|
|
|
|
// EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
|
|
// the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
|
|
// Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
|
|
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
|
|
EGL_NONE,
|
|
};
|
|
|
|
const EGLint fl9_3DisplayAttributes[] =
|
|
{
|
|
// These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3.
|
|
// These attributes are used if the call to eglInitialize fails with the default display attributes.
|
|
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
|
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
|
|
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
|
|
// #ifdef EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER
|
|
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
|
|
// #endif
|
|
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
|
|
EGL_NONE,
|
|
};
|
|
|
|
const EGLint warpDisplayAttributes[] =
|
|
{
|
|
// These attributes can be used to request D3D11 WARP.
|
|
// They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes.
|
|
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
|
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE,
|
|
// #ifdef EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER
|
|
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
|
|
// #endif
|
|
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
|
|
EGL_NONE,
|
|
};
|
|
|
|
EGLConfig config = NULL;
|
|
|
|
// eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11.
|
|
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
|
|
if (!eglGetPlatformDisplayEXT)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT");
|
|
}
|
|
|
|
//
|
|
// To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying
|
|
// parameters passed to eglGetPlatformDisplayEXT:
|
|
// 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+.
|
|
// 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again
|
|
// using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3.
|
|
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
|
|
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
|
|
//
|
|
|
|
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
|
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
|
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
|
|
}
|
|
|
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
|
{
|
|
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
|
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
|
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
|
|
}
|
|
|
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
|
{
|
|
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
|
|
mEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
|
|
if (mEglDisplay == EGL_NO_DISPLAY)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to get EGL display");
|
|
}
|
|
|
|
if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE)
|
|
{
|
|
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
|
|
throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL");
|
|
}
|
|
}
|
|
}
|
|
|
|
EGLint numConfigs = 0;
|
|
if ((eglChooseConfig(mEglDisplay, configAttributes, &mEglConfig, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0))
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig");
|
|
}
|
|
|
|
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttributes);
|
|
if (mEglContext == EGL_NO_CONTEXT)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to create EGL context");
|
|
}
|
|
}
|
|
|
|
void OpenGLES::Cleanup()
|
|
{
|
|
if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT)
|
|
{
|
|
eglDestroyContext(mEglDisplay, mEglContext);
|
|
mEglContext = EGL_NO_CONTEXT;
|
|
}
|
|
|
|
if (mEglDisplay != EGL_NO_DISPLAY)
|
|
{
|
|
eglTerminate(mEglDisplay);
|
|
mEglDisplay = EGL_NO_DISPLAY;
|
|
}
|
|
}
|
|
|
|
void OpenGLES::Reset()
|
|
{
|
|
Cleanup();
|
|
Initialize();
|
|
}
|
|
|
|
EGLSurface OpenGLES::CreateSurface(SwapChainPanel^ panel, const Size* renderSurfaceSize, const float* resolutionScale)
|
|
{
|
|
if (!panel)
|
|
{
|
|
throw Exception::CreateException(E_INVALIDARG, L"SwapChainPanel parameter is invalid");
|
|
}
|
|
|
|
if (renderSurfaceSize != nullptr && resolutionScale != nullptr)
|
|
{
|
|
throw Exception::CreateException(E_INVALIDARG, L"A size and a scale can't both be specified");
|
|
}
|
|
|
|
EGLSurface surface = EGL_NO_SURFACE;
|
|
|
|
const EGLint surfaceAttributes[] =
|
|
{
|
|
// EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above).
|
|
// If you have compilation issues with it then please update your Visual Studio templates.
|
|
//#if defined(EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER)
|
|
// EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
|
|
//#endif
|
|
EGL_NONE
|
|
};
|
|
|
|
// Create a PropertySet and initialize with the EGLNativeWindowType.
|
|
PropertySet^ surfaceCreationProperties = ref new PropertySet();
|
|
surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), panel);
|
|
|
|
// If a render surface size is specified, add it to the surface creation properties
|
|
if (renderSurfaceSize != nullptr)
|
|
{
|
|
surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(*renderSurfaceSize));
|
|
}
|
|
|
|
// If a resolution scale is specified, add it to the surface creation properties
|
|
if (resolutionScale != nullptr)
|
|
{
|
|
surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(*resolutionScale));
|
|
}
|
|
|
|
surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, reinterpret_cast<EGLNativeWindowType>(surfaceCreationProperties), surfaceAttributes);
|
|
if (surface == EGL_NO_SURFACE)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to create EGL surface");
|
|
}
|
|
|
|
return surface;
|
|
}
|
|
|
|
void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height)
|
|
{
|
|
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
|
|
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
|
|
}
|
|
|
|
void OpenGLES::DestroySurface(const EGLSurface surface)
|
|
{
|
|
if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE)
|
|
{
|
|
eglDestroySurface(mEglDisplay, surface);
|
|
}
|
|
}
|
|
|
|
void OpenGLES::MakeCurrent(const EGLSurface surface)
|
|
{
|
|
if (eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) == EGL_FALSE)
|
|
{
|
|
throw Exception::CreateException(E_FAIL, L"Failed to make EGLSurface current");
|
|
}
|
|
}
|
|
|
|
EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface)
|
|
{
|
|
return (eglSwapBuffers(mEglDisplay, surface));
|
|
}
|