Forgot to add fb_egl.c

This commit is contained in:
Jon Smirl
2005-05-14 03:22:48 +00:00
parent 296428dcf4
commit 5cb977fedf
+798
View File
@@ -0,0 +1,798 @@
/*
* Test egl driver for fb_dri.so
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include "utils.h"
#include "buffers.h"
#include "extensions.h"
#include "framebuffer.h"
#include "renderbuffer.h"
#include "array_cache/acache.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_pipeline.h"
#include "drivers/common/driverfuncs.h"
#include "drirenderbuffer.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"
extern void
fbSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis);
/**
* fb driver-specific driver class derived from _EGLDriver
*/
typedef struct fb_driver
{
_EGLDriver Base; /* base class/object */
GLuint fbStuff;
} fbDriver;
/**
* fb display-specific driver class derived from _EGLDisplay
*/
typedef struct fb_display
{
_EGLDisplay Base; /* base class/object */
void *pFB;
} fbDisplay;
/**
* fb driver-specific screen class derived from _EGLScreen
*/
typedef struct fb_screen
{
_EGLScreen Base;
char fb[NAME_MAX];
} fbScreen;
/**
* fb driver-specific surface class derived from _EGLSurface
*/
typedef struct fb_surface
{
_EGLSurface Base; /* base class/object */
struct gl_framebuffer *mesa_framebuffer;
} fbSurface;
/**
* fb driver-specific context class derived from _EGLContext
*/
typedef struct fb_context
{
_EGLContext Base; /* base class/object */
GLcontext *glCtx;
} fbContext;
static EGLBoolean
fbFillInConfigs(_EGLDisplay *disp, unsigned pixel_bits, unsigned depth_bits,
unsigned stencil_bits, GLboolean have_back_buffer) {
_EGLConfig *configs;
_EGLConfig *c;
unsigned int i, num_configs;
unsigned int depth_buffer_factor;
unsigned int back_buffer_factor;
GLenum fb_format;
GLenum fb_type;
/* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
* enough to add support. Basically, if a context is created with an
* fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
* will never be used.
*/
static const GLenum back_buffer_modes[] = {
GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
};
u_int8_t depth_bits_array[2];
u_int8_t stencil_bits_array[2];
depth_bits_array[0] = depth_bits;
depth_bits_array[1] = depth_bits;
/* Just like with the accumulation buffer, always provide some modes
* with a stencil buffer. It will be a sw fallback, but some apps won't
* care about that.
*/
stencil_bits_array[0] = 0;
stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
back_buffer_factor = (have_back_buffer) ? 2 : 1;
num_configs = depth_buffer_factor * back_buffer_factor * 4;
if (pixel_bits == 16) {
fb_format = GL_RGB;
fb_type = GL_UNSIGNED_SHORT_5_6_5;
} else {
fb_format = GL_RGBA;
fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
configs = calloc(sizeof(*configs), num_configs);
c = configs;
if (!_eglFillInConfigs(c, fb_format, fb_type,
depth_bits_array, stencil_bits_array, depth_buffer_factor,
back_buffer_modes, back_buffer_factor,
GLX_TRUE_COLOR)) {
fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
__func__, __LINE__);
return EGL_FALSE;
}
c = &configs[depth_buffer_factor * back_buffer_factor * 2];
if (!_eglFillInConfigs(c, fb_format, fb_type,
depth_bits_array, stencil_bits_array, depth_buffer_factor,
back_buffer_modes, back_buffer_factor,
GLX_DIRECT_COLOR)) {
fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
__func__, __LINE__);
return EGL_FALSE;
}
/* Mark the visual as slow if there are "fake" stencil bits.
*/
for (i = 0, c = configs; i < num_configs; i++, c++) {
if ((c->glmode.stencilBits != 0) && (c->glmode.stencilBits != stencil_bits)) {
c->glmode.visualRating = GLX_SLOW_CONFIG;
}
}
for (i = 0, c = configs; i < num_configs; i++, c++)
_eglAddConfig(disp, c);
free(configs);
return EGL_TRUE;
}
static EGLBoolean
fbSetupFramebuffer(fbDisplay *disp, char *fbdev)
{
int fd;
char dev[20];
struct fb_var_screeninfo varInfo;
struct fb_fix_screeninfo fixedInfo;
snprintf(dev, sizeof(dev), "/dev/%s", fbdev);
/* open the framebuffer device */
fd = open(dev, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Error opening %s: %s\n", fbdev, strerror(errno));
return EGL_FALSE;
}
/* get the original variable screen info */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varInfo)) {
fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
strerror(errno));
return EGL_FALSE;
}
/* Turn off hw accels (otherwise mmap of mmio region will be
* refused)
*/
if (varInfo.accel_flags) {
varInfo.accel_flags = 0;
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varInfo)) {
fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
strerror(errno));
return EGL_FALSE;
}
}
/* Get the fixed screen info */
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixedInfo)) {
fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
strerror(errno));
return EGL_FALSE;
}
/* mmap the framebuffer into our address space */
disp->pFB = (caddr_t)mmap(0, /* start */
fixedInfo.smem_len, /* bytes */
PROT_READ | PROT_WRITE, /* prot */
MAP_SHARED, /* flags */
fd, /* fd */
0); /* offset */
if (disp->pFB == (caddr_t)-1) {
fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
strerror(errno));
return EGL_FALSE;
}
return EGL_TRUE;
}
const char *sysfs = "/sys/class/graphics";
static EGLBoolean
fbInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
{
_EGLDisplay *disp = _eglLookupDisplay(dpy);
fbDisplay *display;
fbScreen *s;
_EGLScreen *scrn;
char c;
unsigned int i, x, y, r;
DIR *dir;
FILE *file;
struct dirent *dirent;
char path[NAME_MAX];
/* Switch display structure to one with our private fields */
display = calloc(1, sizeof(*display));
display->Base = *disp;
_eglHashInsert(_eglGlobal.Displays, disp->Handle, display);
free(disp);
*major = 1;
*minor = 0;
dir = opendir(sysfs);
if (!dir)
return EGL_FALSE;
while (dirent = readdir(dir)) {
if (dirent->d_name[0] != 'f')
continue;
if (dirent->d_name[1] != 'b')
continue;
if (fbSetupFramebuffer(display, dirent->d_name) == EGL_FALSE)
continue;
/* Create a screen */
s = (fbScreen *) calloc(1, sizeof(fbScreen));
if (!s)
return EGL_FALSE;
strncpy(s->fb, dirent->d_name, NAME_MAX);
scrn = &s->Base;
_eglInitScreen(scrn);
_eglAddScreen(&display->Base, scrn);
snprintf(path, sizeof(path), "%s/%s/modes", sysfs, s->fb);
file = fopen(path, "r");
while (fgets(path, sizeof(path), file)) {
sscanf(path, "%c:%ux%u-%u", &c, &x, &y, &r);
_eglAddMode(scrn, x, y, r * 1000, path);
}
fclose(file);
fbFillInConfigs(&display->Base, 32, 24, 8, 1);
}
closedir(dir);
drv->Initialized = EGL_TRUE;
return EGL_TRUE;
}
static fbDisplay *
Lookup_fbDisplay(EGLDisplay dpy)
{
_EGLDisplay *d = _eglLookupDisplay(dpy);
return (fbDisplay *) d;
}
static fbScreen *
Lookup_fbScreen(EGLDisplay dpy, EGLScreenMESA screen)
{
_EGLScreen *s = _eglLookupScreen(dpy, screen);
return (fbScreen *) s;
}
static fbContext *
Lookup_fbContext(EGLContext ctx)
{
_EGLContext *c = _eglLookupContext(ctx);
return (fbContext *) c;
}
static fbSurface *
Lookup_fbSurface(EGLSurface surf)
{
_EGLSurface *s = _eglLookupSurface(surf);
return (fbSurface *) s;
}
static EGLBoolean
fbTerminate(_EGLDriver *drv, EGLDisplay dpy)
{
fbDisplay *display = Lookup_fbDisplay(dpy);
_eglCleanupDisplay(&display->Base);
free(display);
free(drv);
return EGL_TRUE;
}
static const GLubyte *
get_string(GLcontext *ctx, GLenum pname)
{
(void) ctx;
switch (pname) {
case GL_RENDERER:
return (const GLubyte *) "Mesa dumb framebuffer";
default:
return NULL;
}
}
static void
update_state( GLcontext *ctx, GLuint new_state )
{
/* not much to do here - pass it on */
_swrast_InvalidateState( ctx, new_state );
_swsetup_InvalidateState( ctx, new_state );
_ac_InvalidateState( ctx, new_state );
_tnl_InvalidateState( ctx, new_state );
}
/**
* Called by ctx->Driver.GetBufferSize from in core Mesa to query the
* current framebuffer size.
*/
static void
get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
{
*width = buffer->Width;
*height = buffer->Height;
}
static void
viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
{
_mesa_ResizeBuffersMESA();
}
static void
init_core_functions( struct dd_function_table *functions )
{
functions->GetString = get_string;
functions->UpdateState = update_state;
functions->ResizeBuffers = _mesa_resize_framebuffer;
functions->GetBufferSize = get_buffer_size;
functions->Viewport = viewport;
functions->Clear = _swrast_Clear; /* could accelerate with blits */
}
static EGLContext
fbCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
{
GLcontext *ctx;
_EGLConfig *conf;
fbContext *c;
_EGLDisplay *disp = _eglLookupDisplay(dpy);
struct dd_function_table functions;
int i;
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;
}
}
c = (fbContext *) calloc(1, sizeof(fbContext));
if (!c)
return EGL_NO_CONTEXT;
_eglInitContext(&c->Base);
c->Base.Display = disp;
c->Base.Config = conf;
c->Base.DrawSurface = EGL_NO_SURFACE;
c->Base.ReadSurface = EGL_NO_SURFACE;
printf("fbCreateContext\n");
/* generate handle and insert into hash table */
_eglSaveContext(&c->Base);
assert(c->Base.Handle);
/* Init default driver functions then plug in our FBdev-specific functions
*/
_mesa_init_driver_functions(&functions);
init_core_functions(&functions);
ctx = c->glCtx = _mesa_create_context(&conf->glmode, NULL, &functions, (void *)c);
if (!c->glCtx) {
_mesa_free(c);
return GL_FALSE;
}
/* Create module contexts */
_swrast_CreateContext( ctx );
_ac_CreateContext( ctx );
_tnl_CreateContext( ctx );
_swsetup_CreateContext( ctx );
_swsetup_Wakeup( ctx );
/* swrast init -- need to verify these tests - I just plucked the
* numbers out of the air. (KW)
*/
{
struct swrast_device_driver *swdd;
swdd = _swrast_GetDeviceDriverReference( ctx );
}
/* use default TCL pipeline */
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
tnl->Driver.RunPipeline = _tnl_run_pipeline;
}
_mesa_enable_sw_extensions(ctx);
return c->Base.Handle;
}
static EGLSurface
fbCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
{
int i;
for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
switch (attrib_list[i]) {
/* no attribs at this time */
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface");
return EGL_NO_SURFACE;
}
}
printf("eglCreateWindowSurface()\n");
/* XXX unfinished */
return EGL_NO_SURFACE;
}
static EGLSurface
fbCreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
{
_EGLConfig *conf;
EGLint i;
conf = _eglLookupConfig(drv, dpy, config);
if (!conf) {
_eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface");
return EGL_NO_SURFACE;
}
for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
switch (attrib_list[i]) {
/* no attribs at this time */
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
return EGL_NO_SURFACE;
}
}
if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) {
_eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface");
return EGL_NO_SURFACE;
}
printf("eglCreatePixmapSurface()\n");
return EGL_NO_SURFACE;
}
static EGLSurface
fbCreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
{
_EGLConfig *conf;
EGLint i, width = 0, height = 0, largest, texFormat, texTarget, mipmapTex;
fbSurface *surf;
conf = _eglLookupConfig(drv, dpy, config);
if (!conf) {
_eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
return EGL_NO_SURFACE;
}
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;
case EGL_LARGEST_PBUFFER:
largest = attrib_list[++i];
break;
case EGL_TEXTURE_FORMAT:
texFormat = attrib_list[++i];
break;
case EGL_TEXTURE_TARGET:
texTarget = attrib_list[++i];
break;
case EGL_MIPMAP_TEXTURE:
mipmapTex = attrib_list[++i];
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
return EGL_NO_SURFACE;
}
}
if (width <= 0 || height <= 0) {
_eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface(width or height)");
return EGL_NO_SURFACE;
}
surf = (fbSurface *) calloc(1, sizeof(fbSurface));
if (!surf)
return EGL_NO_SURFACE;
surf->Base.Config = conf;
surf->Base.Type = EGL_PBUFFER_BIT;
surf->Base.Width = width;
surf->Base.Height = height;
surf->Base.TextureFormat = texFormat;
surf->Base.TextureTarget = texTarget;
surf->Base.MipmapTexture = mipmapTex;
surf->Base.MipmapLevel = 0;
surf->Base.SwapInterval = 0;
printf("eglCreatePbufferSurface()\n");
/* insert into hash table */
_eglSaveSurface(&surf->Base);
assert(surf->Base.Handle);
return surf->Base.Handle;
}
static EGLBoolean
fbDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
{
fbSurface *fs = Lookup_fbSurface(surface);
_eglRemoveSurface(&fs->Base);
if (fs->Base.IsBound) {
fs->Base.DeletePending = EGL_TRUE;
}
else {
free(fs);
}
return EGL_TRUE;
}
static EGLBoolean
fbDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
{
fbContext *fc = Lookup_fbContext(context);
_eglRemoveContext(&fc->Base);
if (fc->Base.IsBound) {
fc->Base.DeletePending = EGL_TRUE;
}
else {
free(fc);
}
return EGL_TRUE;
}
static EGLBoolean
fbMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
{
fbSurface *readSurf = Lookup_fbSurface(read);
fbSurface *drawSurf = Lookup_fbSurface(draw);
fbContext *ctx = Lookup_fbContext(context);
EGLBoolean b;
b = _eglMakeCurrent(drv, dpy, draw, read, context);
if (!b)
return EGL_FALSE;
if (ctx) {
_mesa_make_current( ctx->glCtx,
drawSurf->mesa_framebuffer,
readSurf->mesa_framebuffer);
} else
_mesa_make_current( NULL, NULL, NULL );
printf("eglMakeCurrent()\n");
return EGL_TRUE;
}
static const char *
fbQueryString(_EGLDriver *drv, EGLDisplay dpy, EGLint name)
{
if (name == EGL_EXTENSIONS) {
return "EGL_MESA_screen_surface";
}
else {
return _eglQueryString(drv, dpy, name);
}
}
/**
* Create a drawing surface which can be directly displayed on a screen.
*/
static EGLSurface
fbCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
const EGLint *attrib_list)
{
_EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
fbDisplay *display = Lookup_fbDisplay(dpy);
fbSurface *surface;
EGLSurface surf;
const GLboolean swDepth = config->glmode.depthBits > 0;
const GLboolean swAlpha = config->glmode.alphaBits > 0;
const GLboolean swAccum = config->glmode.accumRedBits > 0;
const GLboolean swStencil = config->glmode.stencilBits > 0;
int bytesPerPixel = config->glmode.rgbBits / 8;
int origin = 0;
int width, height, stride;
surface = (fbSurface *)malloc(sizeof(*surface));
surf = _eglInitScreenSurfaceMESA(&surface->Base, drv, dpy, cfg, attrib_list);
if (surf == EGL_NO_SURFACE) {
free(surface);
return EGL_NO_SURFACE;
}
width = surface->Base.Width;
stride = width * bytesPerPixel;
height = surface->Base.Height;
surface->mesa_framebuffer = _mesa_create_framebuffer(&config->glmode);
if (!surface->mesa_framebuffer) {
free(surface);
return EGL_NO_SURFACE;
}
surface->mesa_framebuffer->Width = width;
surface->mesa_framebuffer->Height = height;
{
driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel, origin, stride);
fbSetSpanFunctions(drb, &config->glmode);
drb->Base.Data = display->pFB;
_mesa_add_renderbuffer(surface->mesa_framebuffer,
BUFFER_FRONT_LEFT, &drb->Base);
}
if (config->glmode.doubleBufferMode) {
driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, bytesPerPixel, origin, stride);
fbSetSpanFunctions(drb, &config->glmode);
drb->Base.Data = _mesa_malloc(stride * height);
_mesa_add_renderbuffer(surface->mesa_framebuffer,
BUFFER_BACK_LEFT, &drb->Base);
}
_mesa_add_soft_renderbuffers(surface->mesa_framebuffer,
GL_FALSE, /* color */
swDepth,
swStencil,
swAccum,
0,
GL_FALSE /* aux */);
return surf;
}
/**
* Show the given surface on the named screen.
* If surface is EGL_NO_SURFACE, disable the screen's output.
*/
static EGLBoolean
fbShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
EGLSurface surface, EGLModeMESA m)
{
FILE *file;
char buffer[NAME_MAX];
fbScreen *scrn = Lookup_fbScreen(dpy, screen);
fbSurface *surf = Lookup_fbSurface(surface);
_EGLMode *mode = _eglLookupMode(dpy, m);
if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
return EGL_FALSE;
snprintf(buffer, sizeof(buffer), "%s/%s/mode", sysfs, scrn->fb);
file = fopen(buffer, "r+");
fputs(mode->Name, file);
fclose(file);
snprintf(buffer, sizeof(buffer), "%s/%s/bits_per_pixel", sysfs, scrn->fb);
file = fopen(buffer, "r+");
snprintf(buffer, sizeof(buffer), "%d", surf->Base.Config->glmode.rgbBits);
fputs(buffer, file);
fclose(file);
return EGL_TRUE;
}
/*
* Just to silence warning
*/
extern _EGLDriver *
_eglMain(NativeDisplayType dpy);
/**
* The bootstrap function. Return a new fbDriver object and
* plug in API functions.
*/
_EGLDriver *
_eglMain(NativeDisplayType dpy)
{
fbDriver *fb;
fb = (fbDriver *) calloc(1, sizeof(fbDriver));
if (!fb) {
return NULL;
}
/* First fill in the dispatch table with defaults */
_eglInitDriverFallbacks(&fb->Base);
/* then plug in our fb-specific functions */
fb->Base.Initialize = fbInitialize;
fb->Base.Terminate = fbTerminate;
fb->Base.CreateContext = fbCreateContext;
fb->Base.MakeCurrent = fbMakeCurrent;
fb->Base.CreateWindowSurface = fbCreateWindowSurface;
fb->Base.CreatePixmapSurface = fbCreatePixmapSurface;
fb->Base.CreatePbufferSurface = fbCreatePbufferSurface;
fb->Base.DestroySurface = fbDestroySurface;
fb->Base.DestroyContext = fbDestroyContext;
fb->Base.QueryString = fbQueryString;
fb->Base.CreateScreenSurfaceMESA = fbCreateScreenSurfaceMESA;
fb->Base.ShowSurfaceMESA = fbShowSurfaceMESA;
return &fb->Base;
}