static EGLBoolean droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); _EGLContext *ctx; if (dri2_surf->base.Type != EGL_WINDOW_BIT) return EGL_TRUE; if (dri2_drv->glFlush) { ctx = _eglGetCurrentContext(); if (ctx && ctx->DrawSurface == &dri2_surf->base) dri2_drv->glFlush(); } (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); if (dri2_surf->buffer) droid_window_enqueue_buffer(dri2_surf); (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); return EGL_TRUE; }
/** * Called via eglMakeCurrent(), drv->API.MakeCurrent(). */ static EGLBoolean xdri_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d, _EGLSurface *r, _EGLContext *context) { struct xdri_egl_context *xdri_ctx = lookup_context(context); struct xdri_egl_surface *draw = lookup_surface(d); struct xdri_egl_surface *read = lookup_surface(r); if (!_eglMakeCurrent(drv, dpy, d, r, context)) return EGL_FALSE; /* the symbol is defined in libGL.so */ _glapi_check_multithread(); if (xdri_ctx) { if (!xdri_ctx->driContext->bindContext(xdri_ctx->driContext, draw->driDrawable, read->driDrawable)) { return EGL_FALSE; } } else { _EGLContext *old = _eglGetCurrentContext(); if (old) { xdri_ctx = lookup_context(old); xdri_ctx->driContext->unbindContext(xdri_ctx->driContext); } } return EGL_TRUE; }
EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { _EGLContext *ctx = _eglGetCurrentContext(); _EGLDisplay *disp; _EGLDriver *drv; EGLBoolean ret; if (!ctx) RETURN_EGL_SUCCESS(NULL, EGL_TRUE); disp = ctx->Resource.Display; _eglLockMutex(&disp->Mutex); /* let bad current context imply bad current surface */ if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || _eglGetSurfaceHandle(ctx->DrawSurface) == EGL_NO_SURFACE) RETURN_EGL_ERROR(disp, EGL_BAD_CURRENT_SURFACE, EGL_FALSE); /* a valid current context implies an initialized current display */ assert(disp->Initialized); drv = disp->Driver; ret = drv->API.WaitNative(drv, disp, engine); RETURN_EGL_EVAL(disp, ret); }
EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) { _EGLContext *ctx = _eglGetCurrentContext(); EGLint err = EGL_SUCCESS; _EGLSurface *surf; EGLSurface ret; if (!ctx) RETURN_EGL_SUCCESS(NULL, EGL_NO_SURFACE); switch (readdraw) { case EGL_DRAW: surf = ctx->DrawSurface; break; case EGL_READ: surf = ctx->ReadSurface; break; default: surf = NULL; err = EGL_BAD_PARAMETER; break; } ret = _eglGetSurfaceHandle(surf); RETURN_EGL_ERROR(NULL, err, ret); }
EGLContext EGLAPIENTRY eglGetCurrentContext(void) { _EGLContext *ctx = _eglGetCurrentContext(); EGLContext ret; ret = _eglGetContextHandle(ctx); RETURN_EGL_SUCCESS(NULL, ret); }
EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) { _EGLContext *ctx = _eglGetCurrentContext(); EGLDisplay ret; ret = (ctx) ? _eglGetDisplayHandle(ctx->Resource.Display) : EGL_NO_DISPLAY; RETURN_EGL_SUCCESS(NULL, ret); }
static EGLBoolean egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) { _EGLContext *ctx = _eglGetCurrentContext(); if (engine != EGL_CORE_NATIVE_ENGINE) return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); if (ctx && ctx->DrawSurface) { struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); if (gsurf->native) gsurf->native->wait(gsurf->native); } return EGL_TRUE; }
/* If the backbuffer is on a videocard, this is extraordinarily slow! */ static EGLBoolean fbSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw) { fbContext *context = (fbContext *)_eglGetCurrentContext(); fbSurface *fs = Lookup_fbSurface(draw); struct gl_renderbuffer * front_renderbuffer = fs->mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; void *frontBuffer = front_renderbuffer->Data; int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch; void *backBuffer = fs->mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data; if (!_eglSwapBuffers(drv, dpy, draw)) return EGL_FALSE; if (context) { GLcontext *ctx = context->glCtx; if (ctx->Visual.doubleBufferMode) { int i; int offset = 0; char *tmp = _mesa_malloc(currentPitch); _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ ASSERT(frontBuffer); ASSERT(backBuffer); for (i = 0; i < fs->Base.Height; i++) { _mesa_memcpy(tmp, (char *) backBuffer + offset, currentPitch); _mesa_memcpy((char *) frontBuffer + offset, tmp, currentPitch); offset += currentPitch; } _mesa_free(tmp); } } else { /* XXX this shouldn't be an error but we can't handle it for now */ _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n"); return EGL_FALSE; } return EGL_TRUE; }
static EGLBoolean dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, xcb_xfixes_region_t region) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); _EGLContext *ctx; enum xcb_dri2_attachment_t render_attachment; xcb_dri2_copy_region_cookie_t cookie; if (dri2_drv->glFlush) { ctx = _eglGetCurrentContext(); if (ctx && ctx->DrawSurface == &dri2_surf->base) dri2_drv->glFlush(); } (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); #if 0 /* FIXME: Add support for dri swapbuffers, that'll give us swap * interval and page flipping (at least for fullscreen windows) as * well as the page flip event. Unless surface->SwapBehavior is * EGL_BUFFER_PRESERVED. */ #if __DRI2_FLUSH_VERSION >= 2 if (pdraw->psc->f) (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable); #endif #endif if (dri2_surf->have_fake_front) render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT; else render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT; cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn, dri2_surf->drawable, region, XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, render_attachment); free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL)); return EGL_TRUE; }
static EGLBoolean egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLNativePixmapType target) { struct egl_g3d_display *gdpy = egl_g3d_display(dpy); struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); _EGLContext *ctx = _eglGetCurrentContext(); if (!gsurf->render_texture) return EGL_TRUE; /* flush if the surface is current */ if (ctx && ctx->DrawSurface == &gsurf->base) { struct egl_g3d_context *gctx = egl_g3d_context(ctx); gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); } return gdpy->native->copy_to_pixmap(gdpy->native, target, gsurf->render_texture); }
EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { _EGLContext *ctx = _eglGetCurrentContext(); _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLSurface *surf = _eglLookupSurface(surface, disp); _EGLDriver *drv; EGLBoolean ret; _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv); /* surface must be bound to current context in EGL 1.4 */ if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || surf != ctx->DrawSurface) RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); ret = drv->API.SwapBuffers(drv, disp, surf); RETURN_EGL_EVAL(disp, ret); }
EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) { _EGLDisplay *disp = _eglLockDisplay(dpy); _EGLContext *ctx = _eglGetCurrentContext(); _EGLSurface *surf; _EGLDriver *drv; EGLBoolean ret; _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || ctx->Resource.Display != disp) RETURN_EGL_ERROR(disp, EGL_BAD_CONTEXT, EGL_FALSE); surf = ctx->DrawSurface; if (_eglGetSurfaceHandle(surf) == EGL_NO_SURFACE) RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); ret = drv->API.SwapInterval(drv, disp, surf, interval); RETURN_EGL_EVAL(disp, ret); }
static EGLBoolean swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint num_rects, const EGLint *rects, EGLBoolean preserve) { struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); _EGLContext *ctx = _eglGetCurrentContext(); struct egl_g3d_context *gctx = NULL; struct native_present_control ctrl; /* no-op for pixmap or pbuffer surface */ if (gsurf->base.Type == EGL_PIXMAP_BIT || gsurf->base.Type == EGL_PBUFFER_BIT) return EGL_TRUE; /* or when the surface is single-buffered */ if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) return EGL_TRUE; if (ctx && ctx->DrawSurface == surf) gctx = egl_g3d_context(ctx); /* flush if the surface is current */ if (gctx) { gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); } memset(&ctrl, 0, sizeof(ctrl)); ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT; ctrl.preserve = preserve; ctrl.swap_interval = gsurf->base.SwapInterval; ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE); ctrl.num_rects = num_rects; ctrl.rects = rects; return gsurf->native->present(gsurf->native, &ctrl); }
EGLBoolean _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surface, EGLint attribute, EGLint *value) { switch (attribute) { case EGL_WIDTH: *value = surface->Width; break; case EGL_HEIGHT: *value = surface->Height; break; case EGL_CONFIG_ID: *value = surface->Config->ConfigID; break; case EGL_LARGEST_PBUFFER: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->LargestPbuffer; break; case EGL_TEXTURE_FORMAT: /* texture attributes: only for pbuffers, no error otherwise */ if (surface->Type == EGL_PBUFFER_BIT) *value = surface->TextureFormat; break; case EGL_TEXTURE_TARGET: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->TextureTarget; break; case EGL_MIPMAP_TEXTURE: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->MipmapTexture; break; case EGL_MIPMAP_LEVEL: if (surface->Type == EGL_PBUFFER_BIT) *value = surface->MipmapLevel; break; case EGL_SWAP_BEHAVIOR: *value = surface->SwapBehavior; break; case EGL_RENDER_BUFFER: /* From the EGL_KHR_mutable_render_buffer spec (v12): * * Querying EGL_RENDER_BUFFER returns the buffer which client API * rendering is requested to use. For a window surface, this is the * attribute value specified when the surface was created or last set * via eglSurfaceAttrib. * * In other words, querying a window surface returns the value most * recently *requested* by the user. * * The paragraph continues in the EGL 1.5 spec (2014.08.27): * * For a pbuffer surface, it is always EGL_BACK_BUFFER . For a pixmap * surface, it is always EGL_SINGLE_BUFFER . To determine the actual * buffer being rendered to by a context, call eglQueryContext. */ switch (surface->Type) { default: unreachable("bad EGLSurface type"); case EGL_WINDOW_BIT: *value = surface->RequestedRenderBuffer; break; case EGL_PBUFFER_BIT: *value = EGL_BACK_BUFFER; break; case EGL_PIXMAP_BIT: *value = EGL_SINGLE_BUFFER; break; } break; case EGL_PIXEL_ASPECT_RATIO: *value = surface->AspectRatio; break; case EGL_HORIZONTAL_RESOLUTION: *value = surface->HorizontalResolution; break; case EGL_VERTICAL_RESOLUTION: *value = surface->VerticalResolution; break; case EGL_MULTISAMPLE_RESOLVE: *value = surface->MultisampleResolve; break; case EGL_VG_ALPHA_FORMAT: *value = surface->VGAlphaFormat; break; case EGL_VG_COLORSPACE: *value = surface->VGColorspace; break; case EGL_GL_COLORSPACE_KHR: if (!disp->Extensions.KHR_gl_colorspace) return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); *value = surface->GLColorspace; break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: *value = surface->PostSubBufferSupportedNV; break; case EGL_BUFFER_AGE_EXT: /* Both EXT_buffer_age and KHR_partial_update accept EGL_BUFFER_AGE_EXT. * To be precise, the KHR one accepts EGL_BUFFER_AGE_KHR which is an * alias with the same numeric value. */ if (!disp->Extensions.EXT_buffer_age && !disp->Extensions.KHR_partial_update) return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); _EGLContext *ctx = _eglGetCurrentContext(); EGLint result = drv->API.QueryBufferAge(drv, disp, surface); /* error happened */ if (result < 0) return EGL_FALSE; if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || ctx->DrawSurface != surface) return _eglError(EGL_BAD_SURFACE, "eglQuerySurface"); *value = result; surface->BufferAgeRead = EGL_TRUE; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT: *value = surface->HdrMetadata.display_primary_r.x; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT: *value = surface->HdrMetadata.display_primary_r.y; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT: *value = surface->HdrMetadata.display_primary_g.x; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT: *value = surface->HdrMetadata.display_primary_g.y; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT: *value = surface->HdrMetadata.display_primary_b.x; break; case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT: *value = surface->HdrMetadata.display_primary_b.y; break; case EGL_SMPTE2086_WHITE_POINT_X_EXT: *value = surface->HdrMetadata.white_point.x; break; case EGL_SMPTE2086_WHITE_POINT_Y_EXT: *value = surface->HdrMetadata.white_point.y; break; case EGL_SMPTE2086_MAX_LUMINANCE_EXT: *value = surface->HdrMetadata.max_luminance; break; case EGL_SMPTE2086_MIN_LUMINANCE_EXT: *value = surface->HdrMetadata.min_luminance; break; case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT: *value = surface->HdrMetadata.max_cll; break; case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT: *value = surface->HdrMetadata.max_fall; break; default: return _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface"); } return EGL_TRUE; }
EGLContext eglGetCurrentContext(void) { EGL_DEBUG("%s: %s\n", __FILE__, __func__); EGL_DLSYM(eglGetCurrentContext); return _eglGetCurrentContext(); }
/** * Drivers will typically call this to do the error checking and * update the various IsBound and DeletePending flags. * Then, the driver will do its device-dependent Make-Current stuff. */ EGLBoolean _eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d, EGLSurface r, EGLContext context) { _EGLThreadInfo *t = _eglGetCurrentThread(); _EGLContext *ctx = _eglLookupContext(context); _EGLSurface *draw = _eglLookupSurface(d); _EGLSurface *read = _eglLookupSurface(r); _EGLContext *oldContext = _eglGetCurrentContext(); _EGLSurface *oldDrawSurface = _eglGetCurrentSurface(EGL_DRAW); _EGLSurface *oldReadSurface = _eglGetCurrentSurface(EGL_READ); /* error checking */ if (ctx) { if (draw == NULL || read == NULL) { _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); return EGL_FALSE; } if (draw->Config != ctx->Config) { _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); return EGL_FALSE; } if (read->Config != ctx->Config) { _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); return EGL_FALSE; } } /* * check if the old context or surfaces need to be deleted */ if (oldDrawSurface != NULL) { oldDrawSurface->IsBound = EGL_FALSE; if (oldDrawSurface->DeletePending) { /* make sure we don't try to rebind a deleted surface */ if (draw == oldDrawSurface || draw == oldReadSurface) { draw = NULL; } /* really delete surface now */ drv->API.DestroySurface(drv, dpy, oldDrawSurface->Handle); } } if (oldReadSurface != NULL && oldReadSurface != oldDrawSurface) { oldReadSurface->IsBound = EGL_FALSE; if (oldReadSurface->DeletePending) { /* make sure we don't try to rebind a deleted surface */ if (read == oldDrawSurface || read == oldReadSurface) { read = NULL; } /* really delete surface now */ drv->API.DestroySurface(drv, dpy, oldReadSurface->Handle); } } if (oldContext != NULL) { oldContext->IsBound = EGL_FALSE; if (oldContext->DeletePending) { /* make sure we don't try to rebind a deleted context */ if (ctx == oldContext) { ctx = NULL; } /* really delete context now */ drv->API.DestroyContext(drv, dpy, oldContext->Handle); } } if (ctx) { /* check read/draw again, in case we deleted them above */ if (draw == NULL || read == NULL) { _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); return EGL_FALSE; } ctx->DrawSurface = draw; ctx->ReadSurface = read; ctx->IsBound = EGL_TRUE; draw->IsBound = EGL_TRUE; read->IsBound = EGL_TRUE; } t->CurrentContext = ctx; return EGL_TRUE; }
/** * Called via eglSwapBuffers(), drv->API.SwapBuffers(). */ static EGLBoolean dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct wl_callback *callback; if (dri2_surf->block_swap_buffers) { wl_display_flush(dri2_dpy->wl_dpy); while (dri2_surf->block_swap_buffers) wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); } dri2_surf->block_swap_buffers = EGL_TRUE; callback = wl_surface_frame(dri2_surf->wl_win->surface); wl_callback_add_listener(callback, &frame_listener, dri2_surf); if (dri2_surf->base.Type == EGL_WINDOW_BIT) { pointer_swap( (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = __DRI_BUFFER_FRONT_LEFT; dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = __DRI_BUFFER_BACK_LEFT; swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK); if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = wayland_create_buffer(dri2_surf, dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]); wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0, dri2_surf->base.Width, dri2_surf->base.Height); wl_surface_attach(dri2_surf->wl_win->surface, dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], dri2_surf->dx, dri2_surf->dy); dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1; dri2_surf->wl_win->attached_width = dri2_surf->base.Width; dri2_surf->wl_win->attached_height = dri2_surf->base.Height; /* reset resize growing parameters */ dri2_surf->dx = 0; dri2_surf->dy = 0; wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, dri2_surf->base.Width, dri2_surf->base.Height); } _EGLContext *ctx; if (dri2_drv->glFlush) { ctx = _eglGetCurrentContext(); if (ctx && ctx->DrawSurface == &dri2_surf->base) dri2_drv->glFlush(); } (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); return EGL_TRUE; }
EGLContext EGLAPIENTRY eglGetCurrentContext(void) { _EGLContext *ctx = _eglGetCurrentContext(); return _eglGetContextHandle(ctx); }