diff options
Diffstat (limited to 'src/gallium/state_trackers/egl/egl_surface.c')
-rw-r--r-- | src/gallium/state_trackers/egl/egl_surface.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/egl/egl_surface.c b/src/gallium/state_trackers/egl/egl_surface.c new file mode 100644 index 0000000000..69e2d6b708 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_surface.c @@ -0,0 +1,387 @@ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "egl_tracker.h" + +#include "egllog.h" + +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "pipe/p_context.h" + +#include "state_tracker/drm_api.h" + +/* + * Util functions + */ + +static drmModeModeInfoPtr +drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode) +{ + int i; + drmModeModeInfoPtr m = NULL; + + for (i = 0; i < connector->count_modes; i++) { + m = &connector->modes[i]; + if (m->hdisplay == mode->Width && m->vdisplay == mode->Height && m->vrefresh == mode->RefreshRate) + break; + m = &connector->modes[0]; /* if we can't find one, return first */ + } + + return m; +} + +static struct st_framebuffer * +drm_create_framebuffer(const __GLcontextModes *visual, + unsigned width, + unsigned height, + void *priv) +{ + enum pipe_format colorFormat, depthFormat, stencilFormat; + + if (visual->redBits == 5) + colorFormat = PIPE_FORMAT_R5G6B5_UNORM; + else + colorFormat = PIPE_FORMAT_A8R8G8B8_UNORM; + + if (visual->depthBits == 16) + depthFormat = PIPE_FORMAT_Z16_UNORM; + else if (visual->depthBits == 24) + depthFormat = PIPE_FORMAT_S8Z24_UNORM; + else + depthFormat = PIPE_FORMAT_NONE; + + if (visual->stencilBits == 8) + stencilFormat = PIPE_FORMAT_S8Z24_UNORM; + else + stencilFormat = PIPE_FORMAT_NONE; + + return st_create_framebuffer(visual, + colorFormat, + depthFormat, + stencilFormat, + width, + height, + priv); +} + +static void +drm_create_texture(_EGLDisplay *dpy, + struct drm_screen *scrn, + unsigned w, unsigned h) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct pipe_screen *screen = dev->screen; + struct pipe_surface *surface; + struct pipe_texture *texture; + struct pipe_texture templat; + struct pipe_buffer *buf = NULL; + unsigned pitch = 0; + + memset(&templat, 0, sizeof(templat)); + templat.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY; + templat.target = PIPE_TEXTURE_2D; + templat.last_level = 0; + templat.depth[0] = 1; + templat.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templat.width[0] = w; + templat.height[0] = h; + pf_get_block(templat.format, &templat.block); + + texture = screen->texture_create(dev->screen, + &templat); + + if (!texture) + goto err_tex; + + surface = screen->get_tex_surface(screen, + texture, + 0, + 0, + 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + if (!surface) + goto err_surf; + + scrn->tex = texture; + scrn->surface = surface; + scrn->front.width = w; + scrn->front.height = h; + scrn->front.pitch = pitch; + dev->api->local_handle_from_texture(dev->api, screen, texture, + &scrn->front.pitch, &scrn->front.handle); + if (0) + goto err_handle; + + return; + +err_handle: + pipe_surface_reference(&surface, NULL); +err_surf: + pipe_texture_reference(&texture, NULL); +err_tex: + pipe_buffer_reference(&buf, NULL); + return; +} + +/* + * Exported functions + */ + +void +drm_takedown_shown_screen(_EGLDisplay *dpy, struct drm_screen *screen) +{ + struct drm_device *dev = lookup_drm_device(dpy); + + screen->surf = NULL; + + drmModeSetCrtc( + dev->drmFD, + screen->crtcID, + 0, // FD + 0, 0, + NULL, 0, // List of output ids + NULL); + + drmModeRmFB(dev->drmFD, screen->fbID); + drmModeFreeFB(screen->fb); + screen->fb = NULL; + + pipe_surface_reference(&screen->surface, NULL); + pipe_texture_reference(&screen->tex, NULL); + pipe_buffer_reference(&screen->buffer, NULL); + + screen->shown = 0; +} + +_EGLSurface * +drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list) +{ + return NULL; +} + + +_EGLSurface * +drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list) +{ + return NULL; +} + + +_EGLSurface * +drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, + const EGLint *attrib_list) +{ + int i; + int width = -1; + int height = -1; + struct drm_surface *surf = NULL; + __GLcontextModes *visual; + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + case EGL_WIDTH: + width = attrib_list[++i]; + break; + case EGL_HEIGHT: + height = attrib_list[++i]; + break; + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface"); + return EGL_NO_SURFACE; + } + } + + if (width < 1 || height < 1) { + _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface"); + return NULL; + } + + surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface)); + if (!surf) + goto err; + + if (!_eglInitSurface(drv, &surf->base, EGL_PBUFFER_BIT, conf, attrib_list)) + goto err_surf; + + surf->w = width; + surf->h = height; + + visual = drm_visual_from_config(conf); + surf->stfb = drm_create_framebuffer(visual, + width, + height, + (void*)surf); + drm_visual_modes_destroy(visual); + + return &surf->base; + +err_surf: + free(surf); +err: + return NULL; +} + +_EGLSurface * +drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cfg, + const EGLint *attrib_list) +{ + EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list); + + return surf; +} + +EGLBoolean +drm_show_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, + _EGLScreen *screen, + _EGLSurface *surface, _EGLMode *mode) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_surface *surf = lookup_drm_surface(surface); + struct drm_screen *scrn = lookup_drm_screen(screen); + int ret; + unsigned int i, k; + + if (scrn->shown) + drm_takedown_shown_screen(dpy, scrn); + + + drm_create_texture(dpy, scrn, mode->Width, mode->Height); + if (!scrn->buffer) + return EGL_FALSE; + + ret = drmModeAddFB(dev->drmFD, + scrn->front.width, scrn->front.height, + 32, 32, scrn->front.pitch, + scrn->front.handle, + &scrn->fbID); + + if (ret) + goto err_bo; + + scrn->fb = drmModeGetFB(dev->drmFD, scrn->fbID); + if (!scrn->fb) + goto err_bo; + + /* find a fitting crtc */ + { + drmModeConnector *con = scrn->connector; + + scrn->mode = drm_find_mode(con, mode); + if (!scrn->mode) + goto err_fb; + + for (k = 0; k < con->count_encoders; k++) { + drmModeEncoder *enc = drmModeGetEncoder(dev->drmFD, con->encoders[k]); + for (i = 0; i < dev->res->count_crtcs; i++) { + if (enc->possible_crtcs & (1<<i)) { + /* save the ID */ + scrn->crtcID = dev->res->crtcs[i]; + + /* skip the rest */ + i = dev->res->count_crtcs; + k = dev->res->count_encoders; + } + } + drmModeFreeEncoder(enc); + } + } + + ret = drmModeSetCrtc(dev->drmFD, + scrn->crtcID, + scrn->fbID, + 0, 0, + &scrn->connectorID, 1, + scrn->mode); + + if (ret) + goto err_crtc; + + + if (scrn->dpms) + drmModeConnectorSetProperty(dev->drmFD, + scrn->connectorID, + scrn->dpms->prop_id, + DRM_MODE_DPMS_ON); + + surf->screen = scrn; + + scrn->surf = surf; + scrn->shown = 1; + + return EGL_TRUE; + +err_crtc: + scrn->crtcID = 0; + +err_fb: + drmModeRmFB(dev->drmFD, scrn->fbID); + drmModeFreeFB(scrn->fb); + scrn->fb = NULL; + +err_bo: + pipe_surface_reference(&scrn->surface, NULL); + pipe_texture_reference(&scrn->tex, NULL); + pipe_buffer_reference(&scrn->buffer, NULL); + + return EGL_FALSE; +} + +EGLBoolean +drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface) +{ + struct drm_surface *surf = lookup_drm_surface(surface); + if (!_eglIsSurfaceBound(&surf->base)) { + if (surf->screen) + drm_takedown_shown_screen(dpy, surf->screen); + st_unreference_framebuffer(surf->stfb); + free(surf); + } + return EGL_TRUE; +} + +EGLBoolean +drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_surface *surf = lookup_drm_surface(draw); + struct pipe_surface *back_surf; + + if (!surf) + return EGL_FALSE; + + /* error checking */ + if (!_eglSwapBuffers(drv, dpy, draw)) + return EGL_FALSE; + + st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf); + + if (back_surf) { + + st_notify_swapbuffers(surf->stfb); + + if (surf->screen) { + surf->user->pipe->surface_copy(surf->user->pipe, + surf->screen->surface, + 0, 0, + back_surf, + 0, 0, + surf->w, surf->h); + surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL); + +#ifdef DRM_MODE_FEATURE_DIRTYFB + /* TODO query connector property to see if this is needed */ + drmModeDirtyFB(dev->drmFD, surf->screen->fbID, NULL, 0); +#else + (void)dev; +#endif + + /* TODO more stuff here */ + } + } + + return EGL_TRUE; +} |