mirror of https://gitlab.freedesktop.org/mesa/mesa
egl: Add a basic Windows driver
This is enough to run wglgears ported to EGL (desktop GL) Reviewed By: Bill Kristiansen <billkris@microsoft.com> Acked-by: Roland Scheidegger <sroland@vmware.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12727>
This commit is contained in:
parent
06e95693fb
commit
3415bf0268
|
@ -22,6 +22,691 @@
|
|||
*/
|
||||
|
||||
#include <egldriver.h>
|
||||
#include <egllog.h>
|
||||
#include <eglcurrent.h>
|
||||
#include <eglcontext.h>
|
||||
#include <eglsurface.h>
|
||||
|
||||
struct _egl_driver _eglDriver;
|
||||
#include "egl_wgl.h"
|
||||
|
||||
#include <stw_device.h>
|
||||
#include <stw_pixelformat.h>
|
||||
#include <stw_context.h>
|
||||
#include <stw_framebuffer.h>
|
||||
|
||||
#include <GL/wglext.h>
|
||||
|
||||
#include <pipe/p_screen.h>
|
||||
|
||||
#include <mapi/glapi/glapi.h>
|
||||
|
||||
static EGLBoolean
|
||||
wgl_match_config(const _EGLConfig *conf, const _EGLConfig *criteria)
|
||||
{
|
||||
if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0)
|
||||
return EGL_FALSE;
|
||||
|
||||
if (!_eglMatchConfig(conf, criteria))
|
||||
return EGL_FALSE;
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
static struct wgl_egl_config *
|
||||
wgl_add_config(_EGLDisplay *disp, const struct stw_pixelformat_info *stw_config, int id, EGLint surface_type)
|
||||
{
|
||||
struct wgl_egl_config *conf;
|
||||
struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
|
||||
_EGLConfig base;
|
||||
unsigned int double_buffer;
|
||||
int wgl_shifts[4] = { -1, -1, -1, -1 };
|
||||
unsigned int wgl_sizes[4] = { 0, 0, 0, 0 };
|
||||
_EGLConfig *matching_config;
|
||||
EGLint num_configs = 0;
|
||||
EGLint config_id;
|
||||
|
||||
_eglInitConfig(&base, disp, id);
|
||||
|
||||
double_buffer = (stw_config->pfd.dwFlags & PFD_DOUBLEBUFFER) != 0;
|
||||
|
||||
if (stw_config->pfd.iPixelType != PFD_TYPE_RGBA)
|
||||
return NULL;
|
||||
|
||||
wgl_sizes[0] = stw_config->pfd.cRedBits;
|
||||
wgl_sizes[1] = stw_config->pfd.cGreenBits;
|
||||
wgl_sizes[2] = stw_config->pfd.cBlueBits;
|
||||
wgl_sizes[3] = stw_config->pfd.cAlphaBits;
|
||||
|
||||
base.RedSize = stw_config->pfd.cRedBits;
|
||||
base.GreenSize = stw_config->pfd.cGreenBits;
|
||||
base.BlueSize = stw_config->pfd.cBlueBits;
|
||||
base.AlphaSize = stw_config->pfd.cAlphaBits;
|
||||
base.BufferSize = stw_config->pfd.cColorBits;
|
||||
|
||||
wgl_shifts[0] = stw_config->pfd.cRedShift;
|
||||
wgl_shifts[1] = stw_config->pfd.cGreenShift;
|
||||
wgl_shifts[2] = stw_config->pfd.cBlueShift;
|
||||
wgl_shifts[3] = stw_config->pfd.cAlphaShift;
|
||||
|
||||
if (stw_config->pfd.cAccumBits) {
|
||||
/* Don't expose visuals with the accumulation buffer. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
|
||||
base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
|
||||
|
||||
base.DepthSize = stw_config->pfd.cDepthBits;
|
||||
base.StencilSize = stw_config->pfd.cStencilBits;
|
||||
base.Samples = stw_config->stvis.samples;
|
||||
base.SampleBuffers = base.Samples > 1;
|
||||
|
||||
base.NativeRenderable = EGL_TRUE;
|
||||
|
||||
if (surface_type & EGL_PBUFFER_BIT) {
|
||||
base.BindToTextureRGB = stw_config->bindToTextureRGB;
|
||||
if (base.AlphaSize > 0)
|
||||
base.BindToTextureRGBA = stw_config->bindToTextureRGBA;
|
||||
}
|
||||
|
||||
if (double_buffer) {
|
||||
surface_type &= ~EGL_PIXMAP_BIT;
|
||||
}
|
||||
|
||||
if (!(stw_config->pfd.dwFlags & PFD_DRAW_TO_WINDOW)) {
|
||||
surface_type &= ~EGL_WINDOW_BIT;
|
||||
}
|
||||
|
||||
if (!surface_type)
|
||||
return NULL;
|
||||
|
||||
base.SurfaceType = surface_type;
|
||||
base.RenderableType = disp->ClientAPIs;
|
||||
base.Conformant = disp->ClientAPIs;
|
||||
|
||||
base.MinSwapInterval = 0;
|
||||
base.MaxSwapInterval = 1;
|
||||
|
||||
if (!_eglValidateConfig(&base, EGL_FALSE)) {
|
||||
_eglLog(_EGL_DEBUG, "wgl: failed to validate config %d", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config_id = base.ConfigID;
|
||||
base.ConfigID = EGL_DONT_CARE;
|
||||
base.SurfaceType = EGL_DONT_CARE;
|
||||
num_configs = _eglFilterArray(disp->Configs, (void **)&matching_config, 1,
|
||||
(_EGLArrayForEach)wgl_match_config, &base);
|
||||
|
||||
if (num_configs == 1) {
|
||||
conf = (struct wgl_egl_config *)matching_config;
|
||||
|
||||
if (!conf->stw_config[double_buffer])
|
||||
conf->stw_config[double_buffer] = stw_config;
|
||||
else
|
||||
/* a similar config type is already added (unlikely) => discard */
|
||||
return NULL;
|
||||
}
|
||||
else if (num_configs == 0) {
|
||||
conf = calloc(1, sizeof * conf);
|
||||
if (conf == NULL)
|
||||
return NULL;
|
||||
|
||||
conf->stw_config[double_buffer] = stw_config;
|
||||
|
||||
memcpy(&conf->base, &base, sizeof base);
|
||||
conf->base.SurfaceType = 0;
|
||||
conf->base.ConfigID = config_id;
|
||||
|
||||
_eglLinkConfig(&conf->base);
|
||||
}
|
||||
else {
|
||||
unreachable("duplicates should not be possible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conf->base.SurfaceType |= surface_type;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
static EGLBoolean
|
||||
wgl_add_configs(_EGLDisplay *disp, HDC hdc)
|
||||
{
|
||||
unsigned int config_count = 0;
|
||||
unsigned surface_type = EGL_PBUFFER_BIT | (hdc ? EGL_WINDOW_BIT : 0);
|
||||
|
||||
// This is already a filtered set of what the driver supports,
|
||||
// and there's no further filtering needed per-visual
|
||||
for (unsigned i = 1; stw_pixelformat_get_info(i) != NULL; i++) {
|
||||
|
||||
struct wgl_egl_config *wgl_conf = wgl_add_config(disp, stw_pixelformat_get_info(i),
|
||||
config_count + 1, surface_type);
|
||||
|
||||
if (wgl_conf) {
|
||||
if (wgl_conf->base.ConfigID == config_count + 1)
|
||||
config_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return (config_count != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
wgl_display_destroy(_EGLDisplay *disp)
|
||||
{
|
||||
free(disp);
|
||||
}
|
||||
|
||||
static EGLBoolean
|
||||
wgl_initialize_impl(_EGLDisplay *disp, HDC hdc)
|
||||
{
|
||||
struct wgl_egl_display *wgl_dpy;
|
||||
const char* err;
|
||||
|
||||
wgl_dpy = calloc(1, sizeof * wgl_dpy);
|
||||
if (!wgl_dpy)
|
||||
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
||||
|
||||
disp->DriverData = (void *)wgl_dpy;
|
||||
|
||||
if (!stw_init_screen(hdc)) {
|
||||
err = "wgl: failed to initialize screen";
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wgl_dpy->screen = stw_get_device()->screen;
|
||||
|
||||
disp->ClientAPIs = 0;
|
||||
if (_eglIsApiValid(EGL_OPENGL_API))
|
||||
disp->ClientAPIs |= EGL_OPENGL_BIT;
|
||||
if (_eglIsApiValid(EGL_OPENGL_ES_API))
|
||||
disp->ClientAPIs |= EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
|
||||
|
||||
disp->Extensions.KHR_no_config_context = EGL_TRUE;
|
||||
disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
|
||||
disp->Extensions.MESA_query_driver = EGL_TRUE;
|
||||
|
||||
/* Report back to EGL the bitmask of priorities supported */
|
||||
disp->Extensions.IMG_context_priority =
|
||||
wgl_dpy->screen->get_param(wgl_dpy->screen, PIPE_CAP_CONTEXT_PRIORITY_MASK);
|
||||
|
||||
disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
|
||||
|
||||
if (wgl_dpy->screen->is_format_supported(wgl_dpy->screen,
|
||||
PIPE_FORMAT_B8G8R8A8_SRGB,
|
||||
PIPE_TEXTURE_2D, 0, 0,
|
||||
PIPE_BIND_RENDER_TARGET))
|
||||
disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
|
||||
|
||||
disp->Extensions.KHR_create_context = EGL_TRUE;
|
||||
disp->Extensions.KHR_reusable_sync = EGL_TRUE;
|
||||
|
||||
#if 0
|
||||
disp->Extensions.KHR_image_base = EGL_TRUE;
|
||||
disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
|
||||
if (wgl_dpy->image->base.version >= 5 &&
|
||||
wgl_dpy->image->createImageFromTexture) {
|
||||
disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
|
||||
disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE;
|
||||
|
||||
if (wgl_renderer_query_integer(wgl_dpy,
|
||||
__wgl_RENDERER_HAS_TEXTURE_3D))
|
||||
disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!wgl_add_configs(disp, hdc)) {
|
||||
err = "wgl: failed to add configs";
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return EGL_TRUE;
|
||||
|
||||
cleanup:
|
||||
wgl_display_destroy(disp);
|
||||
return _eglError(EGL_NOT_INITIALIZED, err);
|
||||
}
|
||||
|
||||
static EGLBoolean
|
||||
wgl_initialize(_EGLDisplay *disp)
|
||||
{
|
||||
EGLBoolean ret = EGL_FALSE;
|
||||
struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
|
||||
|
||||
/* In the case where the application calls eglMakeCurrent(context1),
|
||||
* eglTerminate, then eglInitialize again (without a call to eglReleaseThread
|
||||
* or eglMakeCurrent(NULL) before that), wgl_dpy structure is still
|
||||
* initialized, as we need it to be able to free context1 correctly.
|
||||
*
|
||||
* It would probably be safest to forcibly release the display with
|
||||
* wgl_display_release, to make sure the display is reinitialized correctly.
|
||||
* However, the EGL spec states that we need to keep a reference to the
|
||||
* current context (so we cannot call wgl_make_current(NULL)), and therefore
|
||||
* we would leak context1 as we would be missing the old display connection
|
||||
* to free it up correctly.
|
||||
*/
|
||||
if (wgl_dpy) {
|
||||
wgl_dpy->ref_count++;
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
switch (disp->Platform) {
|
||||
case _EGL_PLATFORM_SURFACELESS:
|
||||
ret = wgl_initialize_impl(disp, NULL);
|
||||
break;
|
||||
case _EGL_PLATFORM_WINDOWS:
|
||||
ret = wgl_initialize_impl(disp, disp->PlatformDisplay);
|
||||
break;
|
||||
default:
|
||||
unreachable("Callers ensure we cannot get here.");
|
||||
return EGL_FALSE;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return EGL_FALSE;
|
||||
|
||||
wgl_dpy = wgl_egl_display(disp);
|
||||
wgl_dpy->ref_count++;
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement display reference count, and free up display if necessary.
|
||||
*/
|
||||
static void
|
||||
wgl_display_release(_EGLDisplay *disp)
|
||||
{
|
||||
struct wgl_egl_display *wgl_dpy;
|
||||
|
||||
if (!disp)
|
||||
return;
|
||||
|
||||
wgl_dpy = wgl_egl_display(disp);
|
||||
|
||||
assert(wgl_dpy->ref_count > 0);
|
||||
wgl_dpy->ref_count--;
|
||||
|
||||
if (wgl_dpy->ref_count > 0)
|
||||
return;
|
||||
|
||||
_eglCleanupDisplay(disp);
|
||||
wgl_display_destroy(disp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via eglTerminate(), drv->Terminate().
|
||||
*
|
||||
* This must be guaranteed to be called exactly once, even if eglTerminate is
|
||||
* called many times (without a eglInitialize in between).
|
||||
*/
|
||||
static EGLBoolean
|
||||
wgl_terminate(_EGLDisplay *disp)
|
||||
{
|
||||
/* Release all non-current Context/Surfaces. */
|
||||
_eglReleaseDisplayResources(disp);
|
||||
|
||||
wgl_display_release(disp);
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via eglCreateContext(), drv->CreateContext().
|
||||
*/
|
||||
static _EGLContext *
|
||||
wgl_create_context(_EGLDisplay *disp, _EGLConfig *conf,
|
||||
_EGLContext *share_list, const EGLint *attrib_list)
|
||||
{
|
||||
struct wgl_egl_context *wgl_ctx;
|
||||
struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
|
||||
struct wgl_egl_context *wgl_ctx_shared = wgl_egl_context(share_list);
|
||||
struct stw_context *shared =
|
||||
wgl_ctx_shared ? wgl_ctx_shared->ctx : NULL;
|
||||
struct wgl_egl_config *wgl_config = wgl_egl_config(conf);
|
||||
const struct stw_pixelformat_info *stw_config;
|
||||
|
||||
wgl_ctx = malloc(sizeof * wgl_ctx);
|
||||
if (!wgl_ctx) {
|
||||
_eglError(EGL_BAD_ALLOC, "eglCreateContext");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_eglInitContext(&wgl_ctx->base, disp, conf, attrib_list))
|
||||
goto cleanup;
|
||||
|
||||
/* The EGL_EXT_create_context_robustness spec says:
|
||||
*
|
||||
* "Add to the eglCreateContext context creation errors: [...]
|
||||
*
|
||||
* * If the reset notification behavior of <share_context> and the
|
||||
* newly created context are different then an EGL_BAD_MATCH error is
|
||||
* generated."
|
||||
*/
|
||||
if (share_list && share_list->ResetNotificationStrategy !=
|
||||
wgl_ctx->base.ResetNotificationStrategy) {
|
||||
_eglError(EGL_BAD_MATCH, "eglCreateContext");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* The EGL_KHR_create_context_no_error spec says:
|
||||
*
|
||||
* "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
|
||||
* used to create <share_context> does not match the value of
|
||||
* EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
|
||||
*/
|
||||
if (share_list && share_list->NoError != wgl_ctx->base.NoError) {
|
||||
_eglError(EGL_BAD_MATCH, "eglCreateContext");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
unsigned profile_mask = 0;
|
||||
switch (wgl_ctx->base.ClientAPI) {
|
||||
case EGL_OPENGL_ES_API:
|
||||
profile_mask = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
|
||||
break;
|
||||
case EGL_OPENGL_API:
|
||||
if ((wgl_ctx->base.ClientMajorVersion >= 4
|
||||
|| (wgl_ctx->base.ClientMajorVersion == 3
|
||||
&& wgl_ctx->base.ClientMinorVersion >= 2))
|
||||
&& wgl_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
|
||||
profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
else if (wgl_ctx->base.ClientMajorVersion == 3 &&
|
||||
wgl_ctx->base.ClientMinorVersion == 1)
|
||||
profile_mask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
else
|
||||
profile_mask = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
break;
|
||||
default:
|
||||
_eglError(EGL_BAD_PARAMETER, "eglCreateContext");
|
||||
free(wgl_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conf != NULL) {
|
||||
/* The config chosen here isn't necessarily
|
||||
* used for surfaces later.
|
||||
* A pixmap surface will use the single config.
|
||||
* This opportunity depends on disabling the
|
||||
* doubleBufferMode check in
|
||||
* src/mesa/main/context.c:check_compatible()
|
||||
*/
|
||||
if (wgl_config->stw_config[1])
|
||||
stw_config = wgl_config->stw_config[1];
|
||||
else
|
||||
stw_config = wgl_config->stw_config[0];
|
||||
}
|
||||
else
|
||||
stw_config = NULL;
|
||||
|
||||
unsigned flags = 0;
|
||||
if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR)
|
||||
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
if (wgl_ctx->base.Flags & EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR)
|
||||
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
wgl_ctx->ctx = stw_create_context_attribs(disp->PlatformDisplay, 0, shared,
|
||||
wgl_ctx->base.ClientMajorVersion,
|
||||
wgl_ctx->base.ClientMinorVersion,
|
||||
flags,
|
||||
profile_mask,
|
||||
stw_config->iPixelFormat);
|
||||
|
||||
if (!wgl_ctx->ctx)
|
||||
goto cleanup;
|
||||
|
||||
return &wgl_ctx->base;
|
||||
|
||||
cleanup:
|
||||
free(wgl_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via eglDestroyContext(), drv->DestroyContext().
|
||||
*/
|
||||
static EGLBoolean
|
||||
wgl_destroy_context(_EGLDisplay *disp, _EGLContext *ctx)
|
||||
{
|
||||
struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
|
||||
struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
|
||||
|
||||
if (_eglPutContext(ctx)) {
|
||||
stw_destroy_context(wgl_ctx->ctx);
|
||||
free(wgl_ctx);
|
||||
}
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
static EGLBoolean
|
||||
wgl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
|
||||
{
|
||||
struct wgl_egl_surface *wgl_surf = wgl_egl_surface(surf);
|
||||
|
||||
if (!_eglPutSurface(surf))
|
||||
return EGL_TRUE;
|
||||
|
||||
struct stw_context *ctx = stw_current_context();
|
||||
stw_framebuffer_lock(wgl_surf->fb);
|
||||
stw_framebuffer_release_locked(wgl_surf->fb, ctx ? ctx->st : NULL);
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wgl_gl_flush()
|
||||
{
|
||||
static void (*glFlush)(void);
|
||||
static mtx_t glFlushMutex = _MTX_INITIALIZER_NP;
|
||||
|
||||
mtx_lock(&glFlushMutex);
|
||||
if (!glFlush)
|
||||
glFlush = _glapi_get_proc_address("glFlush");
|
||||
mtx_unlock(&glFlushMutex);
|
||||
|
||||
/* if glFlush is not available things are horribly broken */
|
||||
if (!glFlush) {
|
||||
_eglLog(_EGL_WARNING, "wgl: failed to find glFlush entry point");
|
||||
return;
|
||||
}
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via eglMakeCurrent(), drv->MakeCurrent().
|
||||
*/
|
||||
static EGLBoolean
|
||||
wgl_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
|
||||
_EGLSurface *rsurf, _EGLContext *ctx)
|
||||
{
|
||||
struct wgl_egl_display *wgl_dpy = wgl_egl_display(disp);
|
||||
struct wgl_egl_context *wgl_ctx = wgl_egl_context(ctx);
|
||||
_EGLDisplay *old_disp = NULL;
|
||||
struct wgl_egl_display *old_wgl_dpy = NULL;
|
||||
_EGLContext *old_ctx;
|
||||
_EGLSurface *old_dsurf, *old_rsurf;
|
||||
_EGLSurface *tmp_dsurf, *tmp_rsurf;
|
||||
struct stw_framebuffer *ddraw, *rdraw;
|
||||
struct stw_context *cctx;
|
||||
EGLint egl_error = EGL_SUCCESS;
|
||||
|
||||
if (!wgl_dpy)
|
||||
return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent");
|
||||
|
||||
/* make new bindings, set the EGL error otherwise */
|
||||
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
|
||||
return EGL_FALSE;
|
||||
|
||||
if (old_ctx) {
|
||||
struct stw_context *old_cctx = wgl_egl_context(old_ctx)->ctx;
|
||||
old_disp = old_ctx->Resource.Display;
|
||||
old_wgl_dpy = wgl_egl_display(old_disp);
|
||||
|
||||
/* flush before context switch */
|
||||
wgl_gl_flush();
|
||||
|
||||
#if 0
|
||||
if (old_dsurf)
|
||||
wgl_surf_update_fence_fd(old_ctx, disp, old_dsurf);
|
||||
|
||||
/* Disable shared buffer mode */
|
||||
if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
|
||||
old_wgl_dpy->vtbl->set_shared_buffer_mode) {
|
||||
old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
stw_unbind_context(old_cctx);
|
||||
}
|
||||
|
||||
ddraw = (dsurf) ? wgl_egl_surface(dsurf)->fb : NULL;
|
||||
rdraw = (rsurf) ? wgl_egl_surface(rsurf)->fb : NULL;
|
||||
cctx = (wgl_ctx) ? wgl_ctx->ctx : NULL;
|
||||
|
||||
if (cctx || ddraw || rdraw) {
|
||||
if (!stw_make_current(ddraw, rdraw, cctx)) {
|
||||
_EGLContext *tmp_ctx;
|
||||
|
||||
/* stw_make_current failed. We cannot tell for sure why, but
|
||||
* setting the error to EGL_BAD_MATCH is surely better than leaving it
|
||||
* as EGL_SUCCESS.
|
||||
*/
|
||||
egl_error = EGL_BAD_MATCH;
|
||||
|
||||
/* undo the previous _eglBindContext */
|
||||
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf);
|
||||
assert(&wgl_ctx->base == ctx &&
|
||||
tmp_dsurf == dsurf &&
|
||||
tmp_rsurf == rsurf);
|
||||
|
||||
_eglPutSurface(dsurf);
|
||||
_eglPutSurface(rsurf);
|
||||
_eglPutContext(ctx);
|
||||
|
||||
_eglPutSurface(old_dsurf);
|
||||
_eglPutSurface(old_rsurf);
|
||||
_eglPutContext(old_ctx);
|
||||
|
||||
ddraw = (old_dsurf) ? wgl_egl_surface(old_dsurf)->fb : NULL;
|
||||
rdraw = (old_rsurf) ? wgl_egl_surface(old_rsurf)->fb : NULL;
|
||||
cctx = (old_ctx) ? wgl_egl_context(old_ctx)->ctx : NULL;
|
||||
|
||||
/* undo the previous wgl_dpy->core->unbindContext */
|
||||
if (stw_make_current(ddraw, rdraw, cctx)) {
|
||||
#if 0
|
||||
if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
|
||||
old_wgl_dpy->vtbl->set_shared_buffer_mode) {
|
||||
old_wgl_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
return _eglError(egl_error, "eglMakeCurrent");
|
||||
}
|
||||
|
||||
/* We cannot restore the same state as it was before calling
|
||||
* eglMakeCurrent() and the spec isn't clear about what to do. We
|
||||
* can prevent EGL from calling into the DRI driver with no DRI
|
||||
* context bound.
|
||||
*/
|
||||
dsurf = rsurf = NULL;
|
||||
ctx = NULL;
|
||||
|
||||
_eglBindContext(ctx, dsurf, rsurf, &tmp_ctx, &tmp_dsurf, &tmp_rsurf);
|
||||
assert(tmp_ctx == old_ctx && tmp_dsurf == old_dsurf &&
|
||||
tmp_rsurf == old_rsurf);
|
||||
|
||||
_eglLog(_EGL_WARNING, "wgl: failed to rebind the previous context");
|
||||
}
|
||||
else {
|
||||
/* wgl_dpy->core->bindContext succeeded, so take a reference on the
|
||||
* wgl_dpy. This prevents wgl_dpy from being reinitialized when a
|
||||
* EGLDisplay is terminated and then initialized again while a
|
||||
* context is still bound. See wgl_intitialize() for a more in depth
|
||||
* explanation. */
|
||||
wgl_dpy->ref_count++;
|
||||
}
|
||||
}
|
||||
|
||||
wgl_destroy_surface(disp, old_dsurf);
|
||||
wgl_destroy_surface(disp, old_rsurf);
|
||||
|
||||
if (old_ctx) {
|
||||
wgl_destroy_context(disp, old_ctx);
|
||||
wgl_display_release(old_disp);
|
||||
}
|
||||
|
||||
if (egl_error != EGL_SUCCESS)
|
||||
return _eglError(egl_error, "eglMakeCurrent");
|
||||
|
||||
#if 0
|
||||
if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) &&
|
||||
wgl_dpy->vtbl->set_shared_buffer_mode) {
|
||||
/* Always update the shared buffer mode. This is obviously needed when
|
||||
* the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When
|
||||
* EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the
|
||||
* case where external non-EGL API may have changed window's shared
|
||||
* buffer mode since we last saw it.
|
||||
*/
|
||||
bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER);
|
||||
wgl_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
static _EGLSurface*
|
||||
wgl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
|
||||
void *native_window, const EGLint *attrib_list)
|
||||
{
|
||||
struct wgl_egl_config *wgl_conf = wgl_egl_config(conf);
|
||||
|
||||
struct wgl_egl_surface *wgl_surf = calloc(1, sizeof(*wgl_surf));
|
||||
if (!wgl_surf)
|
||||
return NULL;
|
||||
|
||||
if (!_eglInitSurface(&wgl_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, native_window)) {
|
||||
free(wgl_surf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct stw_pixelformat_info *stw_conf = wgl_conf->stw_config[1] ?
|
||||
wgl_conf->stw_config[1] : wgl_conf->stw_config[0];
|
||||
wgl_surf->fb = stw_framebuffer_create(native_window, stw_conf->iPixelFormat, STW_FRAMEBUFFER_EGL_WINDOW);
|
||||
if (!wgl_surf->fb) {
|
||||
free(wgl_surf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stw_framebuffer_unlock(wgl_surf->fb);
|
||||
|
||||
return &wgl_surf->base;
|
||||
}
|
||||
|
||||
static EGLBoolean
|
||||
wgl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
|
||||
{
|
||||
struct wgl_egl_display *wgl_disp = wgl_egl_display(disp);
|
||||
struct wgl_egl_surface *wgl_surf = wgl_egl_surface(draw);
|
||||
|
||||
stw_framebuffer_lock(wgl_surf->fb);
|
||||
HDC hdc = GetDC(wgl_surf->fb->hWnd);
|
||||
BOOL ret = stw_framebuffer_swap_locked(hdc, wgl_surf->fb);
|
||||
ReleaseDC(wgl_surf->fb->hWnd, hdc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct _egl_driver _eglDriver = {
|
||||
.Initialize = wgl_initialize,
|
||||
.Terminate = wgl_terminate,
|
||||
.CreateContext = wgl_create_context,
|
||||
.DestroyContext = wgl_destroy_context,
|
||||
.MakeCurrent = wgl_make_current,
|
||||
.CreateWindowSurface = wgl_create_window_surface,
|
||||
.DestroySurface = wgl_destroy_surface,
|
||||
.GetProcAddress = _glapi_get_proc_address,
|
||||
.SwapBuffers = wgl_swap_buffers,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* 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 (including the next
|
||||
* paragraph) 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <egldriver.h>
|
||||
#include <egldisplay.h>
|
||||
#include <eglconfig.h>
|
||||
|
||||
#include <stw_pixelformat.h>
|
||||
#include <windows.h>
|
||||
|
||||
struct wgl_egl_display
|
||||
{
|
||||
int ref_count;
|
||||
struct pipe_screen *screen;
|
||||
};
|
||||
|
||||
struct wgl_egl_config
|
||||
{
|
||||
_EGLConfig base;
|
||||
const struct stw_pixelformat_info *stw_config[2];
|
||||
};
|
||||
|
||||
struct wgl_egl_context
|
||||
{
|
||||
_EGLContext base;
|
||||
struct stw_context *ctx;
|
||||
};
|
||||
|
||||
struct wgl_egl_surface
|
||||
{
|
||||
_EGLSurface base;
|
||||
struct stw_framebuffer *fb;
|
||||
};
|
||||
|
||||
_EGL_DRIVER_STANDARD_TYPECASTS(wgl_egl)
|
Loading…
Reference in New Issue