Hi, I would like to have the gfxdriver driver I'm writing for the i810/i815 chipset reviewed. Since there's no official i810 framebuffer driver yet included in the kernel, I had to write an i810 framebuffer driver as well. Using a generic gfxdriver in software fallback mode and the i810fb driver, all the examples, gtk-demo and DFPoint work okay.
Overview: The i810 does not have it's own memory, so it has to have a collection of system RAM pages mapped via agpgart into linear space. Also, the i810 cannot be programmed via MMIO and if the acceleration engine is to be used, instructions has to be passed via DMA. The DMA buffer (or ringbuffer in Intel parlance) is not built in to the chipset, but has to be similarly mapped to the framebuffer memory via agpgart. The safest way way I can think of doing this is to have the i810fb driver provide an interface where clients can request for resources (DMA buffer, GART memory, etc), and have them mmapped to userland. To instruct the engine, a client can pass instructions via the user DMA buffer, tell the fbdriver that the instructions are ready, at which point, the fb driver will verify the instructions for correctness before handling them to the hardware. For now, I'm using the ioctl interface for communication. The gfxdriver I have written has accelerated Blit, Blit with colorkeying, Fill rectangles and Draw rectangles. Except for df_neo, (which locks up the accel engine), all examples, gtk-demo and DFBPoint work. The performance increase cannot be said to be blistering though :) Anyway, here's the main file. The complete source for i810fb driver (i810fb-0.0.14-agpgart) and the gfxdriver patch (DFB-0.9.8-i810fb-0.0.14) is in http://www.sourceforge.net/projects.i810fb. I would appreciate any feedback and I'm receptive for any kind of assistance, especially pertaining to the coding. My apologies to all for the long e-mail Tony ---------Start i810.c------------------------------------------------ /* (c) Copyright 2000 convergence integrated media GmbH. All rights reserved. Written by Antonino Daplas <[EMAIL PROTECTED]> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <asm/types.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h> #include <fcntl.h> #include <sys/ioctl.h> #include <malloc.h> #include <directfb.h> #include <core/coredefs.h> #include <core/coretypes.h> #include <core/state.h> #include <core/gfxcard.h> #include <core/surfaces.h> /* need fb handle to get accel, MMIO programming in the i810 is useless */ #include<core/fbdev.h> #include <gfx/convert.h> #include <gfx/util.h> #include <misc/conf.h> #include "i810.h" #define MMIO_SIZE 512 * 1024 #define I810_SUPPORTED_DRAWINGFLAGS \ (DSDRAW_NOFX) #define I810_SUPPORTED_DRAWINGFUNCTIONS \ (DFXL_DRAWRECTANGLE | DFXL_FILLRECTANGLE) #define I810_SUPPORTED_BLITTINGFLAGS \ (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY) #define I810_SUPPORTED_BLITTINGFUNCTIONS \ (DFXL_BLIT) typedef struct { int srcaddr, destaddr, srcpitch, destpitch; int color_value, pixeldepth, blit_color; int colorkey_bit, colorkey; } I810DeviceData; typedef struct { int user_key; volatile __u8 *mmio_base; agp_mem_user dma; agp_mem_user pattern; u32 *dma_buffer; u32 *pattern_buffer; i810_command cmd; } I810DriverData; /* * MMIO access functions */ static inline volatile u8 i810_readb(volatile __u8 *mmio_base, u32 where) { return *((volatile u8 *) (mmio_base + where)); } static inline volatile u16 i810_readw(volatile __u8 *mmio_base, u32 where) { return *((volatile u16 *) (mmio_base + where)); } static inline volatile u32 i810_readl(volatile __u8 *mmio_base, u32 where) { return *((volatile u32 *) (mmio_base + where)); } static inline void i810_writeb(volatile __u8 *mmio_base, u32 where, volatile u8 val) { *((volatile u8 *) (mmio_base + where)) = val; } static inline void i810_writew(volatile __u8 *mmio_base, u32 where, volatile u16 val) { *((volatile u16 *) (mmio_base + where)) = val; } static inline void i810_writel(volatile __u8 *mmio_base, u32 where, volatile u32 val) { *((volatile u32 *) (mmio_base + where)) = val; } static void i810FlushTextureCache(void *drv, void *dev) { I810DriverData *i810drv = (I810DriverData *) drv; i810drv->cmd.command = EMIT_DMA; i810drv->cmd.dma_cmd_start = 0; i810drv->cmd.dma_cmd_dsize = 1; i810drv->dma_buffer[0] = PARSER | FLUSH; if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) DEBUGMSG("flush error"); } static void i810EngineSync(void *drv, void *dev) { I810DriverData *i810drv = (I810DriverData *) drv; int count = 0; while (i810_readw(i810drv->mmio_base, BLTCNTL) & 1 && count++ <= 20000); if (count >= 20000) DEBUGMSG("blit engine lockup"); } /* * Set State routines */ static void i810_set_source(I810DriverData *i810drv, I810DeviceData *i810dev, CardState *state) { CoreSurface *source = state->source; SurfaceBuffer *buffer = source->front_buffer; i810dev->srcaddr = gfxcard_memory_physical(buffer->video.offset); i810dev->srcpitch = buffer->video.pitch; } static void i810_set_destination(I810DriverData *i810drv, I810DeviceData *i810dev, CardState *state) { CoreSurface *destination = state->destination; SurfaceBuffer *buffer = destination->back_buffer; i810dev->destaddr = gfxcard_memory_physical(buffer->video.offset); i810dev->destpitch = buffer->video.pitch; } static void i810_set_colorkey(I810DriverData *i810drv, I810DeviceData *i810dev, CardState *state) { if (state->blittingflags & DSBLIT_SRC_COLORKEY) { i810dev->colorkey_bit = 1 << 8; i810dev->colorkey = state->src_colorkey; } else { i810dev->colorkey_bit = 7 << 8; i810dev->colorkey = state->dst_colorkey; } } static void i810_set_color(I810DriverData *i810drv, I810DeviceData *i810dev, CardState *state) { switch (state->destination->format) { case DSPF_RGB15: i810dev->color_value = PIXEL_RGB15(state->color.r, state->color.g, state->color.b); i810dev->pixeldepth = 2; i810dev->blit_color = BPP16; break; case DSPF_RGB16: i810dev->color_value = PIXEL_RGB16(state->color.r, state->color.g, state->color.b); i810dev->pixeldepth = 2; i810dev->blit_color = BPP16; break; case DSPF_RGB24: i810dev->color_value = PIXEL_RGB24(state->color.r, state->color.g, state->color.b); i810dev->pixeldepth = 3; i810dev->blit_color = BPP24; break; default: BUG("unexpected pixelformat~"); } } static void i810CheckState(void *drv, void *dev, CardState *state, DFBAccelerationMask accel ) { switch (state->destination->format) { case DSPF_RGB15: case DSPF_RGB16: case DSPF_RGB24: break; default: return; } if (!(accel & ~I810_SUPPORTED_DRAWINGFUNCTIONS) && !(state->drawingflags & ~I810_SUPPORTED_DRAWINGFLAGS)) state->accel |= I810_SUPPORTED_DRAWINGFUNCTIONS; if (!(accel & ~I810_SUPPORTED_BLITTINGFUNCTIONS) && !(state->blittingflags & ~I810_SUPPORTED_BLITTINGFLAGS)) { switch (state->source->format) { case DSPF_RGB15: case DSPF_RGB16: case DSPF_RGB24: state->accel |= I810_SUPPORTED_BLITTINGFUNCTIONS; default: } } } static void i810SetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { I810DriverData *i810drv = (I810DriverData *) drv; I810DeviceData *i810dev = (I810DeviceData *) dev; if (state->modified) { if ((state->modified & SMF_SOURCE) && state->source) i810_set_source( i810drv, i810dev, state); if (state->modified & SMF_DESTINATION) i810_set_destination(i810drv, i810dev, state); if (state->modified & SMF_COLOR) i810_set_color(i810drv, i810dev, state); if (state->modified & SMF_BLITTING_FLAGS) { i810dev->colorkey_bit = 0; if (state->blittingflags & (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY)) i810_set_colorkey(i810drv, i810dev, state); } } } static void i810FillRectangle( void *drv, void *dev, DFBRectangle *rect ) { I810DriverData *i810drv = (I810DriverData *) drv; I810DeviceData *i810dev = (I810DeviceData *) dev; int dest; rect->x *= i810dev->pixeldepth; rect->w *= i810dev->pixeldepth; dest = i810dev->destaddr + rect->x + (rect->y * i810dev->destpitch); i810drv->dma_buffer[0] = BLIT | COLOR_BLT | 3; i810drv->dma_buffer[1] = COLOR_COPY_ROP << 16 | i810dev->destpitch | SOLIDPATTERN; i810drv->dma_buffer[2] = rect->h << 16 | rect->w; i810drv->dma_buffer[3] = dest; i810drv->dma_buffer[4] = i810dev->color_value; i810drv->cmd.dma_cmd_start = 0; i810drv->cmd.dma_cmd_dsize = 5; i810drv->cmd.command = EMIT_DMA; if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) DEBUGMSG("fill rectangle error"); } static void i810DrawRectangle( void *drv, void *dev, DFBRectangle *rect ) { I810DriverData *i810drv = (I810DriverData *) drv; I810DeviceData *i810dev = (I810DeviceData *) dev; u32 dest; rect->x *= i810dev->pixeldepth; rect->w *= i810dev->pixeldepth; /* horizontal line 1 */ dest = i810dev->destaddr + rect->x + (rect->y * i810dev->destpitch); i810drv->dma_buffer[0] = BLIT | COLOR_BLT | 3; i810drv->dma_buffer[1] = COLOR_COPY_ROP << 16 | i810dev->destpitch | SOLIDPATTERN; i810drv->dma_buffer[2] = 1 << 16 | rect->w; i810drv->dma_buffer[3] = dest; i810drv->dma_buffer[4] = i810dev->color_value; /* vertical line 2 */ dest += rect->w; i810drv->dma_buffer[5] = BLIT | COLOR_BLT | 3; i810drv->dma_buffer[6] = COLOR_COPY_ROP << 16 | i810dev->destpitch | SOLIDPATTERN; i810drv->dma_buffer[7] = rect->h << 16 | i810dev->pixeldepth; i810drv->dma_buffer[8] = dest; i810drv->dma_buffer[9] = i810dev->color_value; /* vertical line 1 */ dest -= rect->w; i810drv->dma_buffer[10] = BLIT | COLOR_BLT | 3; i810drv->dma_buffer[11] = COLOR_COPY_ROP << 16 | i810dev->destpitch | SOLIDPATTERN; i810drv->dma_buffer[12] = rect->h << 16 | i810dev->pixeldepth; i810drv->dma_buffer[13] = dest; i810drv->dma_buffer[14] = i810dev->color_value; /* horizontal line 2 */ dest += rect->h * i810dev->destpitch; i810drv->dma_buffer[15] = BLIT | COLOR_BLT | 3; i810drv->dma_buffer[16] = COLOR_COPY_ROP << 16 | i810dev->destpitch | SOLIDPATTERN; i810drv->dma_buffer[17] = 1 << 16 | rect->w; i810drv->dma_buffer[18] = dest; i810drv->dma_buffer[19] = i810dev->color_value; i810drv->cmd.dma_cmd_start = 0; i810drv->cmd.dma_cmd_dsize = 20; i810drv->cmd.command = EMIT_DMA; if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) DEBUGMSG("draw rectangle error"); } static void i810Blit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { I810DriverData *i810drv = (I810DriverData *) drv; I810DeviceData *i810dev = (I810DeviceData *) dev; int xdir = INCREMENT, spitch = 0, dpitch = 0, src, dest; rect->x *= i810dev->pixeldepth; dx *= i810dev->pixeldepth; rect->w *= i810dev->pixeldepth; src = i810dev->srcaddr + rect->x + (rect->y * i810dev->srcpitch); dest = i810dev->destaddr + dx + (dy * i810dev->destpitch); if (i810dev->srcaddr == i810dev->destaddr) { spitch = i810dev->srcpitch; dpitch = i810dev->destpitch; if (dx > rect->x && dx < rect->x + rect->w) { xdir = DECREMENT; rect->x += rect->w - 1; dx += rect->w - 1; } if (dy > rect->y && dy < rect->y + rect->h) { i810dev->srcpitch = (-(i810dev->srcpitch)) & 0xFFFF; i810dev->destpitch = (-(i810dev->destpitch)) & 0xFFFF; rect->y += rect->h - 1; dy += rect->h - 1; } src = i810dev->srcaddr + rect->x + (rect->y * spitch); dest = i810dev->destaddr + dx + (dy * dpitch); } i810drv->dma_buffer[0] = BLIT | FULL_BLIT | 0x6 | i810dev->colorkey_bit; i810drv->dma_buffer[1] = xdir | PAT_COPY_ROP << 16 | i810dev->destpitch | DYN_COLOR_EN | i810dev->blit_color; i810drv->dma_buffer[2] = (rect->h << 16) | rect->w; i810drv->dma_buffer[3] = dest; i810drv->dma_buffer[4] = i810dev->srcpitch; i810drv->dma_buffer[5] = src; i810drv->dma_buffer[6] = i810dev->colorkey; i810drv->dma_buffer[7] = i810drv->pattern.offset << 12; i810drv->cmd.dma_cmd_start = 0; i810drv->cmd.dma_cmd_dsize = 8; i810drv->cmd.command = EMIT_DMA; if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) DEBUGMSG("blit error"); } int driver_get_abi_version() { return DFB_GRAPHICS_DRIVER_ABI_VERSION; } int driver_probe( GraphicsDevice *device ) { #ifdef FB_ACCEL_I810 switch (gfxcard_get_accelerator( device )) { case FB_ACCEL_I810: /* Intel 810 */ if (!ioctl(fbdev->fd, I810FB_IOC_AREYOUTHERE, 0)) return 1; } #endif return 0; } void driver_get_info( GraphicsDevice *device, GraphicsDriverInfo *info ) { /* fill driver info structure */ snprintf( info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "Intel 810/810E/810-DC100/815 Driver" ); snprintf( info->vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, "convergence integrated media GmbH" ); info->version.major = 0; info->version.minor = 1; info->driver_data_size = sizeof (I810DriverData); info->device_data_size = sizeof (I810DeviceData); } DFBResult driver_init_driver( GraphicsDevice *device, GraphicsDeviceFuncs *funcs, void *driver_data ) { I810DriverData *i810drv = (I810DriverData *) driver_data; i810drv->mmio_base = (volatile __u8*) gfxcard_map_mmio( device, 0, -1 ); if (!i810drv->mmio_base) return DFB_IO; /* Acquire the framebuffer */ if (ioctl(fbdev->fd, I810FB_IOC_ACQUIREFB, &i810drv->user_key)) return DFB_IO; i810drv->cmd.user_key = i810drv->user_key; i810drv->dma.user_key = i810drv->user_key; /* request for a DMA buffer */ i810drv->dma.type = AGP_DMA; if (ioctl(fbdev->fd, I810FB_IOC_REQUESTAGPMEM, &i810drv->dma)) { i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); return DFB_IO; } i810drv->cmd.surface_key = i810drv->dma.surface_key; /* mmap the DMA buffer */ i810drv->dma_buffer = (u32 *) mmap(NULL, i810drv->dma.pgsize << 12, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev->fd, gfxcard_memory_length() + MMIO_SIZE + (i810drv->dma.offset << 12)); if ((long) i810drv->dma_buffer == -1L) { i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); return DFB_IO; } /* make requested DMA buffer current */ i810drv->cmd.command = UPDATE_DMA; if (ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd)) { i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); return DFB_IO; } /* request for a pattern buffer - may need this as the third operand for some BLIT operations */ i810drv->pattern.type = AGP_SURFACE; i810drv->pattern.pgsize = 1; if (ioctl(fbdev->fd, I810FB_IOC_REQUESTAGPMEM, &i810drv->pattern)) { i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); return DFB_IO; } /* mmap the pattern buffer */ i810drv->pattern_buffer = (u32 *) mmap(NULL, i810drv->pattern.pgsize << 12, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev->fd, gfxcard_memory_length() + MMIO_SIZE + (i810drv->pattern.offset << 12)); if ((long) i810drv->pattern_buffer == -1L) { i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); return DFB_IO; } memset((void *) i810drv->pattern_buffer, 0xFF, i810drv->pattern.pgsize << 12); funcs->CheckState = i810CheckState; funcs->SetState = i810SetState; funcs->FlushTextureCache = i810FlushTextureCache; funcs->DrawRectangle = i810DrawRectangle; funcs->FillRectangle = i810FillRectangle; funcs->Blit = i810Blit; funcs->EngineSync = i810EngineSync; return DFB_OK; } DFBResult driver_init_device( GraphicsDevice *device, GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ) { /* fill device info */ snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "810/810E/810-DC100/815" ); snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "Intel" ); device_info->caps.flags = CCF_CLIPPING; device_info->caps.accel = I810_SUPPORTED_DRAWINGFUNCTIONS | I810_SUPPORTED_BLITTINGFUNCTIONS; device_info->caps.drawing = I810_SUPPORTED_DRAWINGFLAGS; device_info->caps.blitting = I810_SUPPORTED_BLITTINGFLAGS; device_info->limits.surface_byteoffset_alignment = 32 * 4; device_info->limits.surface_pixelpitch_alignment = 32; return DFB_OK; } void driver_init_layers() { } void driver_close_device( GraphicsDevice *device, void *driver_data, void *device_data ) { I810DeviceData *i810dev = (I810DeviceData *) device_data; I810DriverData *i810drv = (I810DriverData *) driver_data; (void) i810dev; (void) i810drv; /* Cannot accurately determine performance, so I'll leave it out */ } void driver_close_driver( GraphicsDevice *device, void *driver_data ) { I810DriverData *i810drv = (I810DriverData *) driver_data; /* unmap all requested buffers */ munmap(i810drv->pattern_buffer, i810drv->pattern.pgsize << 12); munmap(i810drv->dma_buffer, i810drv->dma.pgsize << 12); /* release fb which automatically releases all acquired resources */ i810drv->cmd.command = RELEASE_FB; ioctl(fbdev->fd, I810FB_IOC_COMMAND, &i810drv->cmd); /* unmap mmio */ gfxcard_unmap_mmio( device, i810drv->mmio_base, -1); } -- Info: To unsubscribe send a mail to [EMAIL PROTECTED] with "unsubscribe directfb-dev" as subject.
