Attached are two patches whose objective is to improve DirectFB support
on AMD (formerly National Semiconductor) Geode, especially the older
GX1.
The first patch is a set of diffs for:
nsc-kfb-driver-2.7.7/nsc/nsc_gx1_fb.c
The second patch is a cvs diff from the current DirectFB tree to patch:
gfxdrivers/nsc/nsc.c
KERNEL PATCH
The kernel patch removes an ifdef that is forcing virtual Y resolution
to always match Y resolution which prevents DirectFB from using double
buffering.
1372,1381c1418,1419
< #ifdef CONFIG_FB_GEODE_TV
< if ((par->flags & Display_TVO) && is_tv_supported()) {
< var->xres_virtual = par->xres_virtual;
< var->yres_virtual = par->yres_virtual;
< } else
< #endif
< {
< var->xres_virtual = par->xres;
< var->yres_virtual = par->yres;
< }
---
> var->xres_virtual = par->xres_virtual;
> var->yres_virtual = par->yres_virtual;
There is a second ifdef that may or may not require the same change in
gx1_Geode_set_par() though it hasn't tested well when I've made the
same change there so Its not currently in this patch,
The second kernel driver change is to implement pan display which
appears to be unimplemented at present in the NSC driver. My patch
doesn't implement YWRAP. I've only extensively tested Y panning which
is necessary for DirectFB double buffering
I don't have access to GX2 hardware so I've not implemented these
changes in that driver since I'm not able to test them
DIRECTFB PATCH
The DirectFB patch implements hardware blitting on GX1 graphics though
it is constrained, by hardware, to only blit surfaces whose width
matches the stride of the frame buffer. In other cases it reverts to
the generic software blit. The current driver in CVS only implements
hardware blit on GX2 graphics which doesn't have this stride
limitation.
The hardware accelerated functions for line, rectangle and fill have
been modified to honor dst_offset for Y so they work properly with
double buffering. In the current CVS version these don't honor
dst_offset and are working on the wrong buffer in double buffered mode
half the time. X offset is not currently implemented in this patch
which is focused on making double buffering work.
GEODE COMPRESSION BUFFER
The patch is disabling the Geode's compression buffer when the DirectFB
nsc driver is initialized. This may be a potential drag on performance
since it increases memory traffic on the video memory during refresh.
The compression buffer is very problematic for DirectFB since it is
unaware of it location in video memory. For example at 1024x768 the
compression buffer is mapped right at the start of the second buffer.
You will see display artifacts if its not disabled and you will usually
crash the box as DirectFB overwrites the compression buffer with
randomness. In the future the compression buffer could be moved to the
end of video memory and video ram could be limited to prevent it from
overwriting it.
VIDEO HARDWARE INTERACTION
Moving the compression buffer to the end of video RAM can result in
conflicts if you are using video hardware since the geode_v driver in
geode_v4l2-2.3.2 also uses video memory. In fact geode_v is currently
putting its video buffers in video memory in an area that will also
overlap the second buffer in double buffered mode at 1024x768. This
problem can be remedied by changing geodedrv.c memory buffer offset to:
#define MULTIBUFF_OFFSET 0x0
This puts the video buffer at the very end of video memory. It is
currently offset from the end of video memory by approximately 512K
which causes it to interfere with DirectFB double buffering at
1024x768.
If you set MULTIBUFF_OFFSET to 0, shut off the compression buffer and
limit DirectFB video ram to 3 MB you can run DirectFB double buffered
at 1024x768 and play video at the same time.
-- Ed Millard
1330a1331,1376
> * gx1_geodefb_pan_display
> *
> * Description: This function Pan or Wrap the Display
> * and it looks only at xoffset, yoffset and
> * the FB_VMODE_YWRAP flag.
> * parameters:
> * var: Pointer to fb_var_screeninfo which has the parameters
> * to set the hardware.
> * con: The console which has to be updated with parameters
> * in 'var' structure.
> * info: This is a pointer to the frame buffer information
> * structure.
> * return: error value
> *----------------------------------------------------------------*/
> static int
> gx1_geodefb_pan_display(struct fb_var_screeninfo *var,
> int con, struct fb_info *info)
> {
> int status = 0;
> unsigned short pitch;
> unsigned short xoffset = 0;
>
> assert(var != NULL);
>
> if(var) {
> if (var->xoffset > (var->xres_virtual - var->xres)
> || var->yoffset > (var->yres_virtual - var->yres))
> return -EINVAL;
>
> pitch = gfx_get_display_pitch();
>
> xoffset = var->xoffset * (var->bits_per_pixel >> 3);
>
> gfx_set_display_offset(var->yoffset * pitch + xoffset);
>
> fb_display[con].var.xoffset = var->xoffset;
> fb_display[con].var.yoffset = var->yoffset;
>
> }else{
> status = -EINVAL;
> }
>
> return status;
> }
>
> /*-----------------------------------------------------------------
1372,1381c1418,1419
< #ifdef CONFIG_FB_GEODE_TV
< if ((par->flags & Display_TVO) && is_tv_supported()) {
< var->xres_virtual = par->xres_virtual;
< var->yres_virtual = par->yres_virtual;
< } else
< #endif
< {
< var->xres_virtual = par->xres;
< var->yres_virtual = par->yres;
< }
---
> var->xres_virtual = par->xres_virtual;
> var->yres_virtual = par->yres_virtual;
2089a2128
> fb_pan_display:gx1_geodefb_pan_display,
? gfxdrivers/nsc/nsc.c.new
Index: gfxdrivers/nsc/nsc.c
===================================================================
RCS file: /cvs/directfb/DirectFB/gfxdrivers/nsc/nsc.c,v
retrieving revision 1.9
diff -u -3 -p -r1.9 nsc.c
--- gfxdrivers/nsc/nsc.c 30 Mar 2004 23:42:37 -0000 1.9
+++ gfxdrivers/nsc/nsc.c 13 Jul 2004 22:59:12 -0000
@@ -205,6 +205,7 @@ static bool nscDrawLine(void *drv, void
static bool nscFillRectangle(void *drv, void *dev, DFBRectangle *rect);
static bool nscDrawRectangle(void *drv, void *dev, DFBRectangle *rect);
static bool nscBlit(void *drv, void *dev, DFBRectangle *rect, int dx, int dy);
+static bool nscBlitGu1(void *drv, void *dev, DFBRectangle *rect, int dx, int dy);
static void gxEngineSync(void *drv, void *dev)
{
@@ -227,6 +228,7 @@ gxCheckState(void *drv,
{
#if NSC_ACCEL
NSCDriverData *gxdrv = (NSCDriverData *) drv;
+ NSCDeviceData *gxdev = (NSCDeviceData *) dev;
if(state->destination->format != DSPF_RGB16)
return;
@@ -235,15 +237,38 @@ gxCheckState(void *drv,
if(state->source->format != DSPF_RGB16)
return;
- /* if there are no other blitting flags than the supported
- * and the source and destination formats are the same
- */
if (gxdrv->cpu) {
+ /* GU2 - if there are no other blitting flags than the supported
+ * and the source and destination formats are the same
+ */
if (!(state->blittingflags & ~GX_SUPPORTED_BLITTINGFLAGS) &&
state->source && state->source->format != DSPF_RGB24) {
state->accel |= GX_SUPPORTED_BLITTINGFUNCTIONS;
}
- }
+ } else{
+ /* GU1 - source width must match frame buffer strid
+ */
+ if(state->source) {
+ int src_pitch = 0;
+ int dst_pitch = 0;
+
+ if(state->source) {
+ src_pitch = state->source->width * DFB_BYTES_PER_PIXEL(state->source->format);
+ }
+
+ if (state->modified & SMF_DESTINATION) {
+ if(state->destination && state->destination->front_buffer)
+ dst_pitch = state->destination->back_buffer->video.pitch;
+ }
+ if(dst_pitch == 0) {
+ dst_pitch = gxdev->dst_pitch;
+ }
+
+ if(src_pitch == dst_pitch && state->source) {
+ state->accel |= GX_SUPPORTED_BLITTINGFUNCTIONS;
+ }
+ }
+ }
} else {
/* if there are no other drawing flags than the supported */
if (!(state->drawingflags & ~GX_SUPPORTED_DRAWINGFLAGS)) {
@@ -327,15 +352,17 @@ nscDrawLine(void *drv, void *dev, DFBReg
short majorErr;
unsigned short destData;
NSCDeviceData *gxdev = (NSCDeviceData *) dev;
+ int yoffset;
destData = 0; /* Value will be 0x8 (or) 0 */
dx = line->x2 - line->x1; /* delta values */
dy = line->y2 - line->y1;
adx = ABS(dx);
ady = ABS(dy);
+ yoffset = gxdev->dst_offset / gxdev->dst_pitch;
/* Canonical Bresenham stepper.
- * * We use hardware to draw the pixels to take care of alu modes
+ * * We use hardware to draw the pixels to take care of alu modes
* * and whatnot.
*/
Gal_set_raster_operation(0xF0);
@@ -351,7 +378,7 @@ nscDrawLine(void *drv, void *dev, DFBReg
majorErr = (short)(ady << 1);
Gal_bresenham_line((short)line->x1,
- (short)line->y1,
+ (short)line->y1 + yoffset,
(short)adx,
(short)(majorErr - adx),
(short)majorErr,
@@ -367,7 +394,7 @@ nscDrawLine(void *drv, void *dev, DFBReg
vectorMode |= GP_VECTOR_MAJOR_AXIS_POS;
majorErr = (short)(adx << 1);
Gal_bresenham_line((short)line->x1,
- (short)line->y1,
+ (short)line->y1 + yoffset,
(short)ady,
(short)(majorErr - ady),
(short)majorErr,
@@ -381,10 +408,13 @@ static bool
nscFillRectangle(void *drv, void *dev, DFBRectangle *rect)
{
NSCDeviceData *gxdev = (NSCDeviceData *) dev;
+ int yoffset;
Gal_set_raster_operation(0xF0);
Gal_set_solid_pattern(gxdev->Color);
- Gal_pattern_fill(rect->x, rect->y, rect->w, rect->h);
+
+ yoffset = gxdev->dst_offset / gxdev->dst_pitch;
+ Gal_pattern_fill(rect->x, rect->y + yoffset, rect->w, rect->h);
return true;
}
@@ -393,14 +423,18 @@ static bool
nscDrawRectangle(void *drv, void *dev, DFBRectangle *rect)
{
NSCDeviceData *gxdev = (NSCDeviceData *) dev;
+ int yoffset;
Gal_set_raster_operation(0xF0);
Gal_set_solid_pattern(gxdev->Color);
- Gal_pattern_fill(rect->x, rect->y, rect->w, 1);
- Gal_pattern_fill(rect->x, ((rect->y + rect->h) - 1), rect->w, 1);
- Gal_pattern_fill(rect->x, (rect->y + 1), 1, (rect->h - 2));
+
+ yoffset = gxdev->dst_offset / gxdev->dst_pitch;
+
+ Gal_pattern_fill(rect->x, rect->y + yoffset, rect->w, 1);
+ Gal_pattern_fill(rect->x, ((rect->y + yoffset + rect->h) - 1), rect->w, 1);
+ Gal_pattern_fill(rect->x, (rect->y + yoffset + 1), 1, (rect->h - 2));
Gal_pattern_fill(((rect->x + rect->w) - 1),
- (rect->y + 1), 1, (rect->h - 2));
+ (rect->y + yoffset + 1), 1, (rect->h - 2));
return true;
}
@@ -427,6 +461,34 @@ nscBlit(void *drv, void *dev, DFBRectang
return true;
}
+static bool
+nscBlitGu1(void *drv, void *dev, DFBRectangle * rect, int dx, int dy)
+{
+ int result, yoff;
+
+ NSCDeviceData *nscdev = (NSCDeviceData *) dev;
+
+ Gal_set_solid_pattern(nscdev->Color);
+ if (nscdev->v_srcColorkey) {
+ Gal_set_source_transparency(nscdev->src_colorkey, 0xFFFF);
+ }
+#if 0
+ printf("rect x %d y %d w %d h %d dx %d dy %d src_off %x dst_off %x src pitch %x dst pitch %x\n",
+ rect->x, rect->y, rect->w, rect->h, dx, dy,
+ nscdev->src_offset, nscdev->dst_offset,
+ nscdev->src_pitch, nscdev->dst_pitch);
+#endif
+
+ Gal_set_raster_operation(0xCC);
+
+ yoff = nscdev->src_offset / nscdev->src_pitch;
+ result = Gal_screen_to_screen_blt(rect->x, rect->y + yoff, dx, dy,
+ (unsigned short)rect->w,
+ (unsigned short)rect->h);
+
+ return true;
+}
+
/* exported symbols */
static int
@@ -460,6 +522,8 @@ driver_init_driver(GraphicsDevice *
{
NSCDriverData *gxdrv = (NSCDriverData *) driver_data;
+ Gal_set_compression_enable(0);
+
gxdrv->cpu_version = sAdapterInfo.dwCPUVersion;
gxdrv->cpu = 0;
if ((gxdrv->cpu_version & 0xFF) == GFX_CPU_REDCLOUD) {
@@ -477,8 +541,13 @@ driver_init_driver(GraphicsDevice *
funcs->DrawLine = nscDrawLine;
if (gxdrv->cpu) {
funcs->Blit = nscBlit;
+ } else {
+ funcs->Blit = nscBlitGu1;
}
#endif /* NSC_ACCEL */
+
+ /*dfb_config->pollvsync_after = 1;*/
+
return DFB_OK;
}
@@ -487,8 +556,6 @@ driver_init_device(GraphicsDevice *devic
GraphicsDeviceInfo *device_info,
void *driver_data, void *device_data)
{
- NSCDriverData *gxdrv = (NSCDriverData *) driver_data;
-
snprintf(device_info->name,
DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "NSC GX1/GX2 driver version");
snprintf(device_info->vendor,
@@ -497,10 +564,8 @@ driver_init_device(GraphicsDevice *devic
device_info->caps.flags = CCF_NOTRIEMU;
device_info->caps.accel = GX_SUPPORTED_DRAWINGFUNCTIONS;
device_info->caps.drawing = GX_SUPPORTED_DRAWINGFLAGS;
- if (gxdrv->cpu) {
- device_info->caps.accel |= GX_SUPPORTED_BLITTINGFUNCTIONS;
- device_info->caps.blitting = GX_SUPPORTED_BLITTINGFLAGS;
- }
+ device_info->caps.accel |= GX_SUPPORTED_BLITTINGFUNCTIONS;
+ device_info->caps.blitting = GX_SUPPORTED_BLITTINGFLAGS;
return DFB_OK;
}