src/video/winrt/SDL_winrtopengles.cpp
author Sam Lantinga <slouken@libsdl.org>
Wed, 02 Aug 2017 10:22:48 -0700
changeset 11175 cbc6a8a5b701
parent 10740 bb53965b659d
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Fixed bug 3690 - SDL2 KMS/DRM render context support

Manuel

The attached patch adds support for KMS/DRM context graphics.

It builds with no problem on X86_64 GNU/Linux systems, provided the needed libraries are present, and on ARM GNU/Linux systems that have KMS/DRM support and a GLES2 implementation.
Tested on Raspberry Pi: KMS/DRM is what the Raspberry Pi will use as default in the near future, once the propietary DispmanX API by Broadcom is overtaken by open graphics stack, it's possible to boot current Raspbian system in KMS mode by adding "dtoverlay=vc4-kms-v3d" to config.txt on Raspbian's boot partition.
X86 systems use KMS right away in every current GNU/Linux system.

Simple build instructions:

$./autogen.sh
$./configure --enable-video-kmsdrm
$make
slouken@8582
     1
/*
slouken@8582
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@8582
     4
slouken@8582
     5
  This software is provided 'as-is', without any express or implied
slouken@8582
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@8582
     7
  arising from the use of this software.
slouken@8582
     8
slouken@8582
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@8582
    10
  including commercial applications, and to alter it and redistribute it
slouken@8582
    11
  freely, subject to the following restrictions:
slouken@8582
    12
slouken@8582
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@8582
    14
     claim that you wrote the original software. If you use this software
slouken@8582
    15
     in a product, an acknowledgment in the product documentation would be
slouken@8582
    16
     appreciated but is not required.
slouken@8582
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@8582
    18
     misrepresented as being the original software.
slouken@8582
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@8582
    20
*/
slouken@8609
    21
#include "../../SDL_internal.h"
slouken@8582
    22
slouken@8582
    23
#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL
slouken@8582
    24
slouken@8582
    25
/* EGL implementation of SDL OpenGL support */
slouken@8582
    26
slouken@8582
    27
#include "SDL_winrtvideo_cpp.h"
slouken@8582
    28
extern "C" {
slouken@8582
    29
#include "SDL_winrtopengles.h"
dludwig@8663
    30
#include "SDL_loadso.h"
dludwig@10740
    31
#include "../SDL_egl_c.h"
slouken@8582
    32
}
slouken@8582
    33
dludwig@8663
    34
/* Windows includes */
dludwig@8663
    35
#include <wrl/client.h>
dludwig@8663
    36
using namespace Windows::UI::Core;
dludwig@8663
    37
dludwig@8663
    38
/* ANGLE/WinRT constants */
dludwig@8663
    39
static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0;
dludwig@9386
    40
#define EGL_PLATFORM_ANGLE_ANGLE                        0x3202
dludwig@9386
    41
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE                   0x3203
dludwig@9386
    42
#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE      0x3204
dludwig@9386
    43
#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE      0x3205
dludwig@9386
    44
#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE             0x3208
dludwig@9386
    45
#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE            0x3209
dludwig@9386
    46
#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE       0x320B
dludwig@9386
    47
#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE  0x320F
dludwig@9386
    48
dludwig@9350
    49
#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER   0x320B
dludwig@9350
    50
dludwig@8663
    51
dludwig@8663
    52
/*
dludwig@8663
    53
 * SDL/EGL top-level implementation
dludwig@8663
    54
 */
slouken@8582
    55
slouken@8582
    56
extern "C" int
dludwig@8663
    57
WINRT_GLES_LoadLibrary(_THIS, const char *path)
dludwig@8663
    58
{
dludwig@8663
    59
    SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
dludwig@8663
    60
slouken@11175
    61
    if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0) != 0) {
dludwig@8663
    62
        return -1;
dludwig@8663
    63
    }
dludwig@8663
    64
dludwig@8663
    65
    /* Load ANGLE/WinRT-specific functions */
dludwig@9211
    66
    CreateWinrtEglWindow_Old_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Old_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow");
dludwig@9211
    67
    if (CreateWinrtEglWindow) {
dludwig@9211
    68
        /* 'CreateWinrtEglWindow' was found, which means that an an older
dludwig@9211
    69
         * version of ANGLE/WinRT is being used.  Continue setting up EGL,
dludwig@9211
    70
         * as appropriate to this version of ANGLE.
dludwig@9211
    71
         */
dludwig@9211
    72
dludwig@9211
    73
        /* Create an ANGLE/WinRT EGL-window */
dludwig@9211
    74
        /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */
dludwig@9211
    75
        CoreWindow ^ native_win = CoreWindow::GetForCurrentThread();
dludwig@9211
    76
        Microsoft::WRL::ComPtr<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(native_win);
dludwig@9211
    77
        HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow));
dludwig@9211
    78
        if (FAILED(result)) {
dludwig@9211
    79
            return -1;
dludwig@9211
    80
        }
dludwig@9211
    81
dludwig@9211
    82
        /* Call eglGetDisplay and eglInitialize as appropriate.  On other
dludwig@9211
    83
         * platforms, this would probably get done by SDL_EGL_LoadLibrary,
dludwig@9211
    84
         * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of
dludwig@9211
    85
         * eglGetDisplay requires that a C++ object be passed into it, so the
dludwig@9211
    86
         * call will be made in this file, a C++ file, instead.
dludwig@9211
    87
         */
dludwig@9211
    88
        Microsoft::WRL::ComPtr<IUnknown> cpp_display = video_data->winrtEglWindow;
dludwig@9211
    89
        _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display);
dludwig@9211
    90
        if (!_this->egl_data->egl_display) {
dludwig@10740
    91
            return SDL_EGL_SetError("Could not get Windows 8.0 EGL display", "eglGetDisplay");
dludwig@9211
    92
        }
dludwig@9350
    93
dludwig@9350
    94
        if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
dludwig@10740
    95
            return SDL_EGL_SetError("Could not initialize Windows 8.0 EGL", "eglInitialize");
dludwig@9350
    96
        }
dludwig@9211
    97
    } else {
dludwig@9350
    98
        /* Declare some ANGLE/EGL initialization property-sets, as suggested by
dludwig@9350
    99
         * MSOpenTech's ANGLE-for-WinRT template apps:
dludwig@9350
   100
         */
dludwig@9350
   101
        const EGLint defaultDisplayAttributes[] =
dludwig@9350
   102
        {
dludwig@9211
   103
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
dludwig@9386
   104
            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
dludwig@9386
   105
            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
dludwig@9350
   106
            EGL_NONE,
dludwig@9350
   107
        };
dludwig@9350
   108
dludwig@9350
   109
        const EGLint fl9_3DisplayAttributes[] =
dludwig@9350
   110
        {
dludwig@9350
   111
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
dludwig@9350
   112
            EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
dludwig@9350
   113
            EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
dludwig@9386
   114
            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
dludwig@9386
   115
            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
dludwig@9350
   116
            EGL_NONE,
dludwig@9350
   117
        };
dludwig@9350
   118
dludwig@9350
   119
        const EGLint warpDisplayAttributes[] =
dludwig@9350
   120
        {
dludwig@9350
   121
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
dludwig@9386
   122
            EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
dludwig@9386
   123
            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
dludwig@9386
   124
            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
dludwig@9211
   125
            EGL_NONE,
dludwig@9211
   126
        };
dludwig@9211
   127
dludwig@9211
   128
        /* 'CreateWinrtEglWindow' was NOT found, which either means that a
dludwig@9211
   129
         * newer version of ANGLE/WinRT is being used, or that we don't have
dludwig@9211
   130
         * a valid copy of ANGLE.
dludwig@9211
   131
         *
dludwig@9211
   132
         * Try loading ANGLE as if it were the newer version.
dludwig@9211
   133
         */
dludwig@9211
   134
        eglGetPlatformDisplayEXT_Function eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_Function)_this->egl_data->eglGetProcAddress("eglGetPlatformDisplayEXT");
dludwig@9211
   135
        if (!eglGetPlatformDisplayEXT) {
dludwig@10740
   136
            return SDL_EGL_SetError("Could not retrieve ANGLE/WinRT display function(s)", "eglGetProcAddress");
dludwig@9211
   137
        }
dludwig@9211
   138
dludwig@9350
   139
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
dludwig@9350
   140
        /* Try initializing EGL at D3D11 Feature Level 10_0+ (which is not
dludwig@9350
   141
         * supported on WinPhone 8.x.
dludwig@9350
   142
         */
dludwig@9350
   143
        _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
dludwig@9211
   144
        if (!_this->egl_data->egl_display) {
dludwig@10740
   145
            return SDL_EGL_SetError("Could not get EGL display for Direct3D 10_0+", "eglGetPlatformDisplayEXT");
dludwig@9211
   146
        }
dludwig@8663
   147
dludwig@9350
   148
        if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE)
dludwig@9350
   149
#endif
dludwig@9350
   150
        {
dludwig@9350
   151
            /* Try initializing EGL at D3D11 Feature Level 9_3, in case the
dludwig@9350
   152
             * 10_0 init fails, or we're on Windows Phone (which only supports
dludwig@9350
   153
             * 9_3).
dludwig@9350
   154
             */
dludwig@9350
   155
            _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
dludwig@9350
   156
            if (!_this->egl_data->egl_display) {
dludwig@10740
   157
                return SDL_EGL_SetError("Could not get EGL display for Direct3D 9_3", "eglGetPlatformDisplayEXT");
dludwig@9350
   158
            }
dludwig@9350
   159
dludwig@9350
   160
            if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
dludwig@9350
   161
                /* Try initializing EGL at D3D11 Feature Level 11_0 on WARP
dludwig@9350
   162
                 * (a Windows-provided, software rasterizer) if all else fails.
dludwig@9350
   163
                 */
dludwig@9350
   164
                _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
dludwig@9350
   165
                if (!_this->egl_data->egl_display) {
dludwig@10740
   166
                    return SDL_EGL_SetError("Could not get EGL display for Direct3D WARP", "eglGetPlatformDisplayEXT");
dludwig@9350
   167
                }
dludwig@9350
   168
dludwig@9350
   169
                if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
dludwig@10740
   170
                    return SDL_EGL_SetError("Could not initialize WinRT 8.x+ EGL", "eglInitialize");
dludwig@9350
   171
                }
dludwig@9350
   172
            }
dludwig@9350
   173
        }
dludwig@8663
   174
    }
dludwig@8663
   175
dludwig@8663
   176
    return 0;
dludwig@8663
   177
}
dludwig@8663
   178
dludwig@8663
   179
extern "C" void
dludwig@8663
   180
WINRT_GLES_UnloadLibrary(_THIS)
dludwig@8663
   181
{
dludwig@8663
   182
    SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
dludwig@8663
   183
dludwig@8663
   184
    /* Release SDL's own COM reference to the ANGLE/WinRT IWinrtEglWindow */
dludwig@8663
   185
    if (video_data->winrtEglWindow) {
dludwig@8663
   186
        video_data->winrtEglWindow->Release();
dludwig@8663
   187
        video_data->winrtEglWindow = nullptr;
dludwig@8663
   188
    }
dludwig@8663
   189
dludwig@8663
   190
    /* Perform the bulk of the unloading */
dludwig@8663
   191
    SDL_EGL_UnloadLibrary(_this);
slouken@8582
   192
}
slouken@8582
   193
slouken@8582
   194
extern "C" {
slouken@8582
   195
SDL_EGL_CreateContext_impl(WINRT)
slouken@8582
   196
SDL_EGL_SwapWindow_impl(WINRT)
slouken@8582
   197
SDL_EGL_MakeCurrent_impl(WINRT)
slouken@8582
   198
}
slouken@8582
   199
slouken@8582
   200
#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */
slouken@8582
   201
slouken@8582
   202
/* vi: set ts=4 sw=4 expandtab: */
slouken@8582
   203