Mesa (gallium-0.2): egl: Add a egl state_tracker that use Gallium

Jakob Bornecrantz wallbraker at kemper.freedesktop.org
Sun Jan 18 14:51:06 UTC 2009


Module: Mesa
Branch: gallium-0.2
Commit: 7047f1755f88d6b1f424904e692edbd03a9d190b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=7047f1755f88d6b1f424904e692edbd03a9d190b

Author: Jakob Bornecrantz <wallbraker at gmail.com>
Date:   Sun Jan 18 15:36:47 2009 +0100

egl: Add a egl state_tracker that use Gallium

	This works on top Gallium and KMS. The only thing that
	does not work currently is swap buffers for shown mesa
	screens. So the only fun thing this will produce is a
	white screen.

	The driver wishing to us the state_tracker needs to
	implement the intrace as define in drm_api.h located
	in gallium/include/state_tracker. And also have a
	working KMS implementation.

---

 src/gallium/include/state_tracker/drm_api.h  |   33 +++
 src/gallium/state_trackers/egl/Makefile      |   29 +++
 src/gallium/state_trackers/egl/egl_context.c |  194 +++++++++++++++
 src/gallium/state_trackers/egl/egl_surface.c |  324 ++++++++++++++++++++++++++
 src/gallium/state_trackers/egl/egl_tracker.c |  217 +++++++++++++++++
 src/gallium/state_trackers/egl/egl_tracker.h |  185 +++++++++++++++
 src/gallium/state_trackers/egl/egl_visual.c  |   85 +++++++
 7 files changed, 1067 insertions(+), 0 deletions(-)

diff --git a/src/gallium/include/state_tracker/drm_api.h b/src/gallium/include/state_tracker/drm_api.h
new file mode 100644
index 0000000..54480fa
--- /dev/null
+++ b/src/gallium/include/state_tracker/drm_api.h
@@ -0,0 +1,33 @@
+
+#ifndef _DRM_API_H_
+#define _DRM_API_H_
+
+struct pipe_screen;
+struct pipe_winsys;
+struct pipe_context;
+
+struct drm_api
+{
+	/**
+	 * Special buffer function
+	 */
+	/*@{*/
+	struct pipe_screen*  (*create_screen)(int drmFB, int pciID);
+	struct pipe_context* (*create_context)(struct pipe_screen *screen);
+	/*@}*/
+
+	/**
+	 * Special buffer function
+	 */
+	/*@{*/
+	struct pipe_buffer* (*buffer_from_handle)(struct pipe_winsys *winsys, const char *name, unsigned handle);
+	unsigned (*handle_from_buffer)(struct pipe_winsys *winsys, struct pipe_buffer *buffer);
+	/*@}*/
+};
+
+/**
+ * A driver needs to export this symbol
+ */
+extern struct drm_api drm_api_hocks;
+
+#endif
diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile
new file mode 100644
index 0000000..17d1a7a
--- /dev/null
+++ b/src/gallium/state_trackers/egl/Makefile
@@ -0,0 +1,29 @@
+TARGET     = libegldrm.a
+CFILES     = $(wildcard ./*.c)
+OBJECTS    = $(patsubst ./%.c,./%.o,$(CFILES))
+GALLIUMDIR = ../..
+TOP        = ../../../..
+
+include ${TOP}/configs/current
+
+CFLAGS += -g -Wall -Werror=implicit-function-declaration -fPIC \
+          $(shell pkg-config --cflags pixman-1 xorg-server) \
+          -I${GALLIUMDIR}/include \
+          -I${GALLIUMDIR}/auxiliary \
+          -I${TOP}/src/mesa/drivers/dri/common \
+          -I${TOP}/src/mesa \
+          -I$(TOP)/include \
+          -I$(TOP)/src/egl/main \
+          ${LIBDRM_CFLAGS}
+
+#############################################
+
+.PHONY	= all clean
+
+all: ${TARGET}
+
+${TARGET}: ${OBJECTS}
+	ar rcs $@ $^
+
+clean:
+	rm -rf ${OBJECTS} ${TARGET}
diff --git a/src/gallium/state_trackers/egl/egl_context.c b/src/gallium/state_trackers/egl/egl_context.c
new file mode 100644
index 0000000..217fe00
--- /dev/null
+++ b/src/gallium/state_trackers/egl/egl_context.c
@@ -0,0 +1,194 @@
+
+#include "utils.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "egl_tracker.h"
+
+#include "egllog.h"
+
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_winsys.h"
+
+#include "state_tracker/st_public.h"
+#include "state_tracker/drm_api.h"
+
+#include "GL/internal/glcore.h"
+
+#define need_GL_ARB_multisample
+#define need_GL_ARB_point_parameters
+#define need_GL_ARB_texture_compression
+#define need_GL_ARB_vertex_buffer_object
+#define need_GL_ARB_vertex_program
+#define need_GL_ARB_window_pos
+#define need_GL_EXT_blend_color
+#define need_GL_EXT_blend_equation_separate
+#define need_GL_EXT_blend_func_separate
+#define need_GL_EXT_blend_minmax
+#define need_GL_EXT_cull_vertex
+#define need_GL_EXT_fog_coord
+#define need_GL_EXT_framebuffer_object
+#define need_GL_EXT_multi_draw_arrays
+#define need_GL_EXT_secondary_color
+#define need_GL_NV_vertex_program
+#include "extension_helper.h"
+
+/**
+ * TODO HACK! FUGLY!
+ * Copied for intel extentions.
+ */
+const struct dri_extension card_extensions[] = {
+	{"GL_ARB_multisample", GL_ARB_multisample_functions},
+	{"GL_ARB_multitexture", NULL},
+	{"GL_ARB_point_parameters", GL_ARB_point_parameters_functions},
+	{"GL_ARB_texture_border_clamp", NULL},
+	{"GL_ARB_texture_compression", GL_ARB_texture_compression_functions},
+	{"GL_ARB_texture_cube_map", NULL},
+	{"GL_ARB_texture_env_add", NULL},
+	{"GL_ARB_texture_env_combine", NULL},
+	{"GL_ARB_texture_env_dot3", NULL},
+	{"GL_ARB_texture_mirrored_repeat", NULL},
+	{"GL_ARB_texture_rectangle", NULL},
+	{"GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions},
+	{"GL_ARB_pixel_buffer_object", NULL},
+	{"GL_ARB_vertex_program", GL_ARB_vertex_program_functions},
+	{"GL_ARB_window_pos", GL_ARB_window_pos_functions},
+	{"GL_EXT_blend_color", GL_EXT_blend_color_functions},
+	{"GL_EXT_blend_equation_separate", GL_EXT_blend_equation_separate_functions},
+	{"GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions},
+	{"GL_EXT_blend_minmax", GL_EXT_blend_minmax_functions},
+	{"GL_EXT_blend_subtract", NULL},
+	{"GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions},
+	{"GL_EXT_fog_coord", GL_EXT_fog_coord_functions},
+	{"GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions},
+	{"GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions},
+	{"GL_EXT_packed_depth_stencil", NULL},
+	{"GL_EXT_pixel_buffer_object", NULL},
+	{"GL_EXT_secondary_color", GL_EXT_secondary_color_functions},
+	{"GL_EXT_stencil_wrap", NULL},
+	{"GL_EXT_texture_edge_clamp", NULL},
+	{"GL_EXT_texture_env_combine", NULL},
+	{"GL_EXT_texture_env_dot3", NULL},
+	{"GL_EXT_texture_filter_anisotropic", NULL},
+	{"GL_EXT_texture_lod_bias", NULL},
+	{"GL_3DFX_texture_compression_FXT1", NULL},
+	{"GL_APPLE_client_storage", NULL},
+	{"GL_MESA_pack_invert", NULL},
+	{"GL_MESA_ycbcr_texture", NULL},
+	{"GL_NV_blend_square", NULL},
+	{"GL_NV_vertex_program", GL_NV_vertex_program_functions},
+	{"GL_NV_vertex_program1_1", NULL},
+	{"GL_SGIS_generate_mipmap", NULL },
+	{NULL, NULL}
+};
+
+EGLContext
+drm_create_context(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
+{
+	struct drm_device *dev = (struct drm_device *)drv;
+	struct drm_context *ctx;
+	struct drm_context *share = NULL;
+	struct st_context *st_share = NULL;
+	_EGLConfig *conf;
+	int i;
+	__GLcontextModes *visual;
+
+	conf = _eglLookupConfig(drv, dpy, config);
+	if (!conf) {
+		_eglError(EGL_BAD_CONFIG, "eglCreateContext");
+		return EGL_NO_CONTEXT;
+	}
+
+	for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+		switch (attrib_list[i]) {
+			/* no attribs defined for now */
+			default:
+				_eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
+				return EGL_NO_CONTEXT;
+		}
+	}
+
+	ctx = (struct drm_context *) calloc(1, sizeof(struct drm_context));
+	if (!ctx)
+		goto err_c;
+
+	_eglInitContext(drv, dpy, &ctx->base, config, attrib_list);
+
+	ctx->pipe = drm_api_hocks.create_context(dev->screen);
+	if (!ctx->pipe)
+		goto err_pipe;
+
+	if (share)
+		st_share = share->st;
+
+	visual = drm_visual_from_config(conf);
+	ctx->st = st_create_context(ctx->pipe, visual, st_share);
+	drm_visual_modes_destroy(visual);
+
+	if (!ctx->st)
+		goto err_gl;
+
+	/* generate handle and insert into hash table */
+	_eglSaveContext(&ctx->base);
+	assert(_eglGetContextHandle(&ctx->base));
+
+	return _eglGetContextHandle(&ctx->base);
+
+err_gl:
+	ctx->pipe->destroy(ctx->pipe);
+err_pipe:
+	free(ctx);
+err_c:
+	return EGL_NO_CONTEXT;
+}
+
+EGLBoolean
+drm_destroy_context(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
+{
+	struct drm_context *c = lookup_drm_context(context);
+	_eglRemoveContext(&c->base);
+	if (c->base.IsBound) {
+		c->base.DeletePending = EGL_TRUE;
+	} else {
+		st_destroy_context(c->st);
+		c->pipe->destroy(c->pipe);
+		free(c);
+	}
+	return EGL_TRUE;
+}
+
+EGLBoolean
+drm_make_current(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
+{
+	struct drm_surface *readSurf = lookup_drm_surface(read);
+	struct drm_surface *drawSurf = lookup_drm_surface(draw);
+	struct drm_context *ctx = lookup_drm_context(context);
+	EGLBoolean b;
+
+	b = _eglMakeCurrent(drv, dpy, draw, read, context);
+	if (!b)
+		return EGL_FALSE;
+
+	if (ctx) {
+		if (!drawSurf || !readSurf)
+			return EGL_FALSE;
+
+		drawSurf->user = ctx;
+		readSurf->user = ctx;
+
+		st_make_current(ctx->st, drawSurf->stfb, readSurf->stfb);
+
+		/* st_resize_framebuffer needs a bound context to work */
+		st_resize_framebuffer(drawSurf->stfb, drawSurf->w, drawSurf->h);
+		st_resize_framebuffer(readSurf->stfb, readSurf->w, readSurf->h);
+	} else {
+		drawSurf->user = NULL;
+		readSurf->user = NULL;
+
+		st_make_current(NULL, NULL, NULL);
+	}
+
+	return EGL_TRUE;
+}
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 0000000..1bd3a91
--- /dev/null
+++ b/src/gallium/state_trackers/egl/egl_surface.c
@@ -0,0 +1,324 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "egl_tracker.h"
+
+#include "egllog.h"
+
+#include "pipe/p_inlines.h"
+
+#include "state_tracker/drm_api.h"
+
+/*
+ * Util functions
+ */
+
+static struct drm_mode_modeinfo *
+drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode)
+{
+	int i;
+	struct drm_mode_modeinfo *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);
+}
+
+/*
+ * Exported functions
+ */
+
+void
+drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen)
+{
+	struct drm_device *dev = (struct drm_device *)drv;
+
+	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_buffer_reference(dev->screen, &screen->buffer, NULL);
+
+	screen->shown = 0;
+}
+
+EGLSurface
+drm_create_window_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
+{
+	return EGL_NO_SURFACE;
+}
+
+
+EGLSurface
+drm_create_pixmap_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
+{
+	return EGL_NO_SURFACE;
+}
+
+
+EGLSurface
+drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+                           const EGLint *attrib_list)
+{
+	int i;
+	int width = -1;
+	int height = -1;
+	struct drm_surface *surf = NULL;
+	__GLcontextModes *visual;
+	_EGLConfig *conf;
+
+	conf = _eglLookupConfig(drv, dpy, config);
+	if (!conf) {
+		_eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
+		return EGL_NO_CONTEXT;
+	}
+
+	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 EGL_NO_SURFACE;
+	}
+
+	surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface));
+	if (!surf)
+		goto err;
+
+	if (!_eglInitSurface(drv, dpy, &surf->base, EGL_PBUFFER_BIT, config, 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);
+
+	_eglSaveSurface(&surf->base);
+	return surf->base.Handle;
+
+err_surf:
+	free(surf);
+err:
+	return EGL_NO_SURFACE;
+}
+
+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,
+                             EGLScreenMESA screen,
+                             EGLSurface surface, EGLModeMESA m)
+{
+	struct drm_device *dev = (struct drm_device *)drv;
+	struct drm_surface *surf = lookup_drm_surface(surface);
+	struct drm_screen *scrn = lookup_drm_screen(dpy, screen);
+	_EGLMode *mode = _eglLookupMode(dpy, m);
+	size_t pitch = 2048 * 4;
+	size_t size = mode->Height * pitch;
+	int ret;
+	unsigned int i, k;
+	void *ptr;
+
+	if (scrn->shown)
+		drm_takedown_shown_screen(drv, scrn);
+
+	scrn->buffer = pipe_buffer_create(dev->screen,
+	                                  0, /* alignment */
+	                                  PIPE_BUFFER_USAGE_GPU_READ_WRITE |
+	                                  PIPE_BUFFER_USAGE_CPU_READ_WRITE,
+	                                  size);
+
+	if (!scrn->buffer)
+		return EGL_FALSE;
+
+	ptr = pipe_buffer_map(dev->screen, scrn->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
+	memset(ptr, 0xFF, size);
+	pipe_buffer_unmap(dev->screen, scrn->buffer);
+
+	scrn->handle = drm_api_hocks.handle_from_buffer(dev->winsys, scrn->buffer);
+
+	ret = drmModeAddFB(dev->drmFD, mode->Width, mode->Height,
+	                   32, 32, pitch,
+	                   scrn->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;
+
+	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_buffer_reference(dev->screen, &scrn->buffer, NULL);
+
+	return EGL_FALSE;
+}
+
+EGLBoolean
+drm_destroy_surface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+	struct drm_surface *surf = lookup_drm_surface(surface);
+	_eglRemoveSurface(&surf->base);
+	if (surf->base.IsBound) {
+		surf->base.DeletePending = EGL_TRUE;
+	} else {
+		if (surf->screen)
+			drm_takedown_shown_screen(drv, surf->screen);
+		st_unreference_framebuffer(surf->stfb);
+		free(surf);
+	}
+	return EGL_TRUE;
+}
+
+EGLBoolean
+drm_swap_buffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+{
+	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;
+
+	back_surf = st_get_framebuffer_surface(surf->stfb,
+	                                       ST_SURFACE_BACK_LEFT);
+
+	if (back_surf) {
+
+		st_notify_swapbuffers(surf->stfb);
+
+		if (surf->screen) {
+			/* TODO stuff here */
+		}
+
+		st_notify_swapbuffers_complete(surf->stfb);
+	}
+
+	return EGL_TRUE;
+}
diff --git a/src/gallium/state_trackers/egl/egl_tracker.c b/src/gallium/state_trackers/egl/egl_tracker.c
new file mode 100644
index 0000000..3ca5acb
--- /dev/null
+++ b/src/gallium/state_trackers/egl/egl_tracker.c
@@ -0,0 +1,217 @@
+
+#include "utils.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "egl_tracker.h"
+
+#include "egllog.h"
+#include "state_tracker/drm_api.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_winsys.h"
+
+/** HACK */
+void* driDriverAPI;
+extern const struct dri_extension card_extensions[];
+
+
+/*
+ * Exported functions
+ */
+
+/**
+ * The bootstrap function.  Return a new drm_driver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy, const char *args)
+{
+	struct drm_device *drm;
+
+	drm = (struct drm_device *) calloc(1, sizeof(struct drm_device));
+	if (!drm) {
+		return NULL;
+	}
+
+	/* First fill in the dispatch table with defaults */
+	_eglInitDriverFallbacks(&drm->base);
+	/* then plug in our Drm-specific functions */
+	drm->base.API.Initialize = drm_initialize;
+	drm->base.API.Terminate = drm_terminate;
+	drm->base.API.CreateContext = drm_create_context;
+	drm->base.API.MakeCurrent = drm_make_current;
+	drm->base.API.CreateWindowSurface = drm_create_window_surface;
+	drm->base.API.CreatePixmapSurface = drm_create_pixmap_surface;
+	drm->base.API.CreatePbufferSurface = drm_create_pbuffer_surface;
+	drm->base.API.DestroySurface = drm_destroy_surface;
+	drm->base.API.DestroyContext = drm_destroy_context;
+	drm->base.API.CreateScreenSurfaceMESA = drm_create_screen_surface_mesa;
+	drm->base.API.ShowScreenSurfaceMESA = drm_show_screen_surface_mesa;
+	drm->base.API.SwapBuffers = drm_swap_buffers;
+
+	drm->base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
+	drm->base.Name = "DRM/Gallium/Win";
+
+	/* enable supported extensions */
+	drm->base.Extensions.MESA_screen_surface = EGL_TRUE;
+	drm->base.Extensions.MESA_copy_context = EGL_TRUE;
+
+	return &drm->base;
+}
+
+static void
+drm_get_device_id(struct drm_device *device)
+{
+	char path[512];
+	FILE *file;
+
+	/* TODO get the real minor */
+	int minor = 0;
+
+	snprintf(path, sizeof(path), "/sys/class/drm/card%d/device/device", minor);
+	file = fopen(path, "r");
+	if (!file) {
+		_eglLog(_EGL_WARNING, "Could not retrive device ID\n");
+		return;
+	}
+
+	fgets(path, sizeof( path ), file);
+	sscanf(path, "%x", &device->deviceID);
+	fclose(file);
+}
+
+static void
+drm_update_res(struct drm_device *dev)
+{
+	drmModeFreeResources(dev->res);
+	dev->res = drmModeGetResources(dev->drmFD);
+}
+
+static void
+drm_add_modes_from_connector(_EGLScreen *screen, drmModeConnectorPtr connector)
+{
+	struct drm_mode_modeinfo *m;
+	int i;
+
+	for (i = 0; i < connector->count_modes; i++) {
+		m = &connector->modes[i];
+		_eglAddNewMode(screen, m->hdisplay, m->vdisplay, m->vrefresh, m->name);
+	}
+}
+
+EGLBoolean
+drm_initialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+	_EGLDisplay *disp = _eglLookupDisplay(dpy);
+	struct drm_device *dev = (struct drm_device *)drv;
+	struct drm_screen *screen = NULL;
+	drmModeConnectorPtr connector = NULL;
+	drmModeResPtr res = NULL;
+	unsigned count_connectors = 0;
+	int num_screens = 0;
+	EGLint i;
+	int fd;
+
+	fd = drmOpen("i915", NULL);
+	if (fd < 0)
+		goto err_fd;
+
+	dev->drmFD = fd;
+	drm_get_device_id(dev);
+
+	dev->screen = drm_api_hocks.create_screen(dev->drmFD, dev->deviceID);
+	if (!dev->screen)
+		goto err_screen;
+	dev->winsys = dev->screen->winsys;
+
+	/* TODO HACK */
+	driInitExtensions(NULL, card_extensions, GL_FALSE);
+
+	drm_update_res(dev);
+	res = dev->res;
+	if (res)
+		count_connectors = res->count_connectors;
+	else
+		_eglLog(_EGL_WARNING, "Could not retrive kms information\n");
+
+	for(i = 0; i < count_connectors && i < MAX_SCREENS; i++) {
+		connector = drmModeGetConnector(fd, res->connectors[i]);
+
+		if (!connector)
+			continue;
+
+		if (connector->connection != DRM_MODE_CONNECTED) {
+			drmModeFreeConnector(connector);
+			continue;
+		}
+
+		screen = malloc(sizeof(struct drm_screen));
+		memset(screen, 0, sizeof(*screen));
+		screen->connector = connector;
+		screen->connectorID = connector->connector_id;
+		_eglInitScreen(&screen->base);
+		_eglAddScreen(disp, &screen->base);
+		drm_add_modes_from_connector(&screen->base, connector);
+		dev->screens[num_screens++] = screen;
+	}
+	dev->count_screens = num_screens;
+
+	/* for now we only have one config */
+	_EGLConfig *config = calloc(1, sizeof(*config));
+	memset(config, 1, sizeof(*config));
+	_eglInitConfig(config, 1);
+	_eglSetConfigAttrib(config, EGL_RED_SIZE, 8);
+	_eglSetConfigAttrib(config, EGL_GREEN_SIZE, 8);
+	_eglSetConfigAttrib(config, EGL_BLUE_SIZE, 8);
+	_eglSetConfigAttrib(config, EGL_ALPHA_SIZE, 8);
+	_eglSetConfigAttrib(config, EGL_BUFFER_SIZE, 32);
+	_eglSetConfigAttrib(config, EGL_DEPTH_SIZE, 24);
+	_eglSetConfigAttrib(config, EGL_STENCIL_SIZE, 8);
+	_eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT);
+	_eglAddConfig(disp, config);
+
+	drv->Initialized = EGL_TRUE;
+
+	*major = 1;
+	*minor = 4;
+
+	return EGL_TRUE;
+
+err_screen:
+	drmClose(fd);
+err_fd:
+	return EGL_FALSE;
+}
+
+EGLBoolean
+drm_terminate(_EGLDriver *drv, EGLDisplay dpy)
+{
+	struct drm_device *dev = (struct drm_device *)drv;
+	struct drm_screen *screen;
+	int i = 0;
+
+	drmFreeVersion(dev->version);
+
+	for (i = 0; i < dev->count_screens; i++) {
+		screen = dev->screens[i];
+
+		if (screen->shown)
+			drm_takedown_shown_screen(drv, screen);
+
+		drmModeFreeConnector(screen->connector);
+		_eglDestroyScreen(&screen->base);
+		dev->screens[i] = NULL;
+	}
+
+	dev->screen->destroy(dev->screen);
+	dev->winsys = NULL;
+
+	drmClose(dev->drmFD);
+
+	_eglCleanupDisplay(_eglLookupDisplay(dpy));
+	free(dev);
+
+	return EGL_TRUE;
+}
diff --git a/src/gallium/state_trackers/egl/egl_tracker.h b/src/gallium/state_trackers/egl/egl_tracker.h
new file mode 100644
index 0000000..df637a5
--- /dev/null
+++ b/src/gallium/state_trackers/egl/egl_tracker.h
@@ -0,0 +1,185 @@
+
+#ifndef _EGL_TRACKER_H_
+#define _EGL_TRACKER_H_
+
+#include <stdint.h>
+
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglglobals.h"
+#include "eglmode.h"
+#include "eglscreen.h"
+#include "eglsurface.h"
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+#include "pipe/p_compiler.h"
+
+#include "state_tracker/st_public.h"
+
+#define MAX_SCREENS 16
+
+struct pipe_winsys;
+struct pipe_screen;
+struct pipe_context;
+struct state_tracker;
+
+struct drm_screen;
+struct drm_context;
+
+struct drm_device
+{
+	_EGLDriver base; /* base class/object */
+
+	/*
+	 * pipe
+	 */
+
+	struct pipe_winsys *winsys;
+	struct pipe_screen *screen;
+
+	/*
+	 * drm
+	 */
+
+	int drmFD;
+	drmVersionPtr version;
+	int deviceID;
+
+	drmModeResPtr res;
+
+	struct drm_screen *screens[MAX_SCREENS];
+	size_t count_screens;
+};
+
+struct drm_surface
+{
+	_EGLSurface base; /* base class/object */
+
+	/*
+	 * pipe
+	 */
+
+
+	struct st_framebuffer *stfb;
+
+	/*
+	 * drm
+	 */
+
+	struct drm_context *user;
+	struct drm_screen *screen;
+
+	int w;
+	int h;
+};
+
+struct drm_context
+{
+	_EGLContext base; /* base class/object */
+
+	/* pipe */
+
+	struct pipe_context *pipe;
+	struct st_context *st;
+};
+
+struct drm_screen
+{
+	_EGLScreen base;
+
+	/*
+	 * pipe
+	 */
+
+	struct pipe_buffer *buffer;
+
+	/*
+	 * drm
+	 */
+
+	/* buffer handle */
+	int handle;
+
+	/* currently only support one connector */
+	drmModeConnectorPtr connector;
+	uint32_t connectorID;
+
+	/* Has this screen been shown */
+	int shown;
+
+	/* Surface that is currently attached to this screen */
+	struct drm_surface *surf;
+
+	/* framebuffer */
+	drmModeFBPtr fb;
+	uint32_t fbID;
+
+	/* crtc and mode used */
+	/*drmModeCrtcPtr crtc;*/
+	uint32_t crtcID;
+
+	struct drm_mode_modeinfo *mode;
+};
+
+
+static INLINE struct drm_context *
+lookup_drm_context(EGLContext context)
+{
+	_EGLContext *c = _eglLookupContext(context);
+	return (struct drm_context *) c;
+}
+
+
+static INLINE struct drm_surface *
+lookup_drm_surface(EGLSurface surface)
+{
+	_EGLSurface *s = _eglLookupSurface(surface);
+	return (struct drm_surface *) s;
+}
+
+static INLINE struct drm_screen *
+lookup_drm_screen(EGLDisplay dpy, EGLScreenMESA screen)
+{
+	_EGLScreen *s = _eglLookupScreen(dpy, screen);
+	return (struct drm_screen *) s;
+}
+
+/**
+ * egl_visual.h
+ */
+/*@{*/
+void drm_visual_modes_destroy(__GLcontextModes *modes);
+__GLcontextModes* drm_visual_modes_create(unsigned count, size_t minimum_size);
+__GLcontextModes* drm_visual_from_config(_EGLConfig *conf);
+/*@}*/
+
+/**
+ * egl_surface.h
+ */
+/*@{*/
+void drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen);
+/*@}*/
+
+/**
+ * All function exported to the egl side.
+ */
+/*@{*/
+EGLBoolean drm_initialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLBoolean drm_terminate(_EGLDriver *drv, EGLDisplay dpy);
+EGLContext drm_create_context(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
+EGLBoolean drm_destroy_context(_EGLDriver *drv, EGLDisplay dpy, EGLContext context);
+EGLSurface drm_create_window_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list);
+EGLSurface drm_create_pixmap_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list);
+EGLSurface drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLSurface drm_create_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg, const EGLint *attrib_list);
+EGLBoolean drm_show_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen, EGLSurface surface, EGLModeMESA m);
+EGLBoolean drm_destroy_surface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface);
+EGLBoolean drm_make_current(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context);
+EGLBoolean drm_swap_buffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw);
+/*@}*/
+
+#endif
diff --git a/src/gallium/state_trackers/egl/egl_visual.c b/src/gallium/state_trackers/egl/egl_visual.c
new file mode 100644
index 0000000..e59f893
--- /dev/null
+++ b/src/gallium/state_trackers/egl/egl_visual.c
@@ -0,0 +1,85 @@
+
+#include "egl_tracker.h"
+
+#include "egllog.h"
+
+void
+drm_visual_modes_destroy(__GLcontextModes *modes)
+{
+   _eglLog(_EGL_DEBUG, "%s", __FUNCTION__);
+
+   while (modes) {
+      __GLcontextModes * const next = modes->next;
+      free(modes);
+      modes = next;
+   }
+}
+
+__GLcontextModes *
+drm_visual_modes_create(unsigned count, size_t minimum_size)
+{
+	/* This code copied from libGLX, and modified */
+	const size_t size = (minimum_size > sizeof(__GLcontextModes))
+		? minimum_size : sizeof(__GLcontextModes);
+	__GLcontextModes * head = NULL;
+	__GLcontextModes ** next;
+	unsigned   i;
+
+	_eglLog(_EGL_DEBUG, "%s %d %d", __FUNCTION__, count, minimum_size);
+
+	next = & head;
+	for (i = 0 ; i < count ; i++) {
+		*next = (__GLcontextModes *) calloc(1, size);
+		if (*next == NULL) {
+			drm_visual_modes_destroy(head);
+			head = NULL;
+			break;
+		}
+
+		(*next)->doubleBufferMode = 1;
+		(*next)->visualID = GLX_DONT_CARE;
+		(*next)->visualType = GLX_DONT_CARE;
+		(*next)->visualRating = GLX_NONE;
+		(*next)->transparentPixel = GLX_NONE;
+		(*next)->transparentRed = GLX_DONT_CARE;
+		(*next)->transparentGreen = GLX_DONT_CARE;
+		(*next)->transparentBlue = GLX_DONT_CARE;
+		(*next)->transparentAlpha = GLX_DONT_CARE;
+		(*next)->transparentIndex = GLX_DONT_CARE;
+		(*next)->xRenderable = GLX_DONT_CARE;
+		(*next)->fbconfigID = GLX_DONT_CARE;
+		(*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
+		(*next)->bindToTextureRgb = GLX_DONT_CARE;
+		(*next)->bindToTextureRgba = GLX_DONT_CARE;
+		(*next)->bindToMipmapTexture = GLX_DONT_CARE;
+		(*next)->bindToTextureTargets = 0;
+		(*next)->yInverted = GLX_DONT_CARE;
+
+		next = & ((*next)->next);
+	}
+
+	return head;
+}
+
+__GLcontextModes *
+drm_visual_from_config(_EGLConfig *conf)
+{
+	__GLcontextModes *visual;
+	(void)conf;
+
+	visual = drm_visual_modes_create(1, sizeof(*visual));
+	visual->redBits = 8;
+	visual->greenBits = 8;
+	visual->blueBits = 8;
+	visual->alphaBits = 8;
+
+	visual->rgbBits = 32;
+	visual->doubleBufferMode = 1;
+
+	visual->depthBits = 24;
+	visual->haveDepthBuffer = visual->depthBits > 0;
+	visual->stencilBits = 8;
+	visual->haveStencilBuffer = visual->stencilBits > 0;
+
+	return visual;
+}




More information about the mesa-commit mailing list