Hardware page flipping on NVIDIA video cards under Linux

Tutorials on how to create your own rigs, pics, movies, and everything that has to do with S-3D at home!
Post Reply
User avatar
Fredz
Petrif-Eyed
Posts: 2255
Joined: Sat Jan 09, 2010 2:06 pm
Location: Perpignan, France
Contact:

Hardware page flipping on NVIDIA video cards under Linux

Post by Fredz »

Following this I've written a new hardware page flipping test application for Linux that should work on most NVIDIA video cards (generation NV03 to NVC0) and with both the proprietary and the free driver (Nouveau).

You can compile it by typing this command :

Code: Select all

gcc -O2 -o pflip-nvidia pflip-nvidia.c
And launch it as root by passing it half the value of your current horizontal resolution (ie. 512 for 1024x768) :

Code: Select all

./pflip-nvidia 512
Then you can type 1 + <enter> to reset the page flipping and 2 + <enter> to set it. If all works well you should see the left half of the screen on the right and vice-versa. You can quit with q + <enter>.

Here is the code (pflip-nvidia.c) :

Code: Select all

/*
NAME
	pflip-nvidia - test hardware page flipping for NVIDIA video cards

SYNOPSIS
	pflip-nvidia <offset>

DESCRIPTION
	pflip-nvidia is used to test hardware page flipping on graphic cards
	supporting standard VGA registers while running an X Server.

	To obtain meaningful results, a virtual screen must be active with an
	horizontal resolution set to the double of the viewport horizontal
	resolution. For example, a 1024x768 viewport with a 2048x768 virtual
	screen.

	The application is controlled using these interactive commands:

	q	quit the application
	1	set the CRTC Start Address Register to 0
	2	set the CRTC Start Address Register to <offset>

OPTIONS
	<offset>
		Set the offset value as a number of pixel columns that should
		correspond to the width of the current viewport. For example
		1920 for a 3840x1080 virtual screen.

AUTHOR
	Frédéric Lopez <http://askyl.blog.free.fr/>

	21 May 2012
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <sys/mman.h>

// Define the "address" and "data" registers for VGA CRTC access
#define VGA_CRTC_ADDR_REG 0x3D4
#define VGA_CRTC_DATA_REG 0x3D5

#define PCI_GET_BUS(devbusfn) ((devbusfn >> 8) & 0xff)
#define PCI_GET_DEVICE(devbusfn) ((devbusfn & 0xff) >> 3)
#define PCI_GET_FUNCTION(devbusfn) (devbusfn & 0x7)

// Set the CRTC Start Adress Register
static void set_vga_start(volatile uint8_t *mem, int offset)
{
	// Set the VGA CRTC Start Address Low Register
	mem[VGA_CRTC_ADDR_REG] = 0x0D;
	mem[VGA_CRTC_DATA_REG] = offset & 0xFF;
	// Set the VGA CRTC Start Address High Register
	mem[VGA_CRTC_ADDR_REG] = 0x0C;
	mem[VGA_CRTC_DATA_REG] = offset >> 8;	
}

int32_t pciReadLong(unsigned short devbusfn, long offset)
{
    char file[25];
    FILE *device;
    short bus = PCI_GET_BUS(devbusfn);
    short dev = PCI_GET_DEVICE(devbusfn);
    short function = PCI_GET_FUNCTION(devbusfn);

    snprintf(file, sizeof(file), "/proc/bus/pci/%02x/%02x.%x", bus, dev, function);
    if ((device = fopen(file, "r")) != NULL)
    {
		int32_t buffer;
		fseek(device, offset, SEEK_SET); 	    			    
		fread(&buffer, sizeof(int32_t), 1, device);
		fclose(device);

		return buffer;
    }
    
    return -1;
}

/* Check if the device is a videocard */
int is_video_card(unsigned short devbusfn)
{
    int32_t pci_class = pciReadLong(devbusfn, 0x9);

	/* The device is a VGA card */
    if (((htonl(pci_class) >> 8) & 0xf) == 0x03)
        return 1;
    else
        return 0;
}

/* Get the register offset */
int get_reg_addr()
{
	int dev, dum, reg_addr, i = 0;
    unsigned short devbusfn;
    char buf[256];
    FILE *proc;
	
    proc = fopen("/proc/bus/pci/devices", "r");
    if (!proc) 
    {
		perror("Can't open /proc/bus/pci/devices !");
        return -1;
    }

    while (fgets(buf, sizeof(buf) - 1, proc)) 
    {
        if (sscanf(buf,"%hx %x %x %x",&devbusfn, &dev, &dum, &reg_addr) != 4)
        	continue;

        /* The card contains an Nvidia chipset */	
        if ((dev >> 16) == 0x10de)
		{
			if (!is_video_card(devbusfn))
				continue;
			i++;
		}
	}
	
	fclose(proc);
	
    if (i == 0)
    	return -1;
    	else return reg_addr;
}

int main(int argc, char *argv[])
{
	int key, offset;
	char *p;
    
    int fd;
    void *map;
    uint64_t res;
    char buf[32];
    volatile uint8_t *m;
    int resfd;

	// Test the number of command-line arguments
	if (argc != 2)
	{
		printf("Usage: pflip-nvidia <offset>\n");
		exit(EXIT_FAILURE);
	}

	// Test if the argument is an integer
	errno = 0;
	offset = strtol(argv[1], &p, 10);
	if (errno != 0 || *p != 0 || p == argv[1])
	{
		printf("Error: offset value must be an integer!\n");
		exit(EXIT_FAILURE);
	}

	// Show interactive commands help
	printf("Quit with 'q'.\n");
	printf("Page 1 with '1'.\n");
	printf("Page 2 with '2'.\n");

	// Find video card register offset	
	res = get_reg_addr();
	if (res == -1)
	{
		printf("Error: no NVIDIA video card found!\n");
		exit(EXIT_FAILURE);
	}

	// Open /dev/mem to map NVIDIA registers
	if ((fd = open("/dev/mem", O_RDWR)) < 0) {
		perror("Fail open :(");
		return -1;
	}

	// Map NVIDIA VGA CRTC registers  
	m = map = mmap(0, 0x2000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, res + 0x601000);
	if (map == MAP_FAILED) {
		perror("FAIL mmap :(");
		return -1;
	}
	
	// Main loop
	while ((key = getchar()) != 'q')
	{
		switch (key)
		{
			case '1' :
				set_vga_start(m, 0);
				printf("Page 1.\n");
				break;
			case '2' :
				set_vga_start(m, offset);
				printf("Page 2.\n");
				break;
		}
	}
	
	printf("Done.\n");
	return EXIT_SUCCESS;
}
On my machine (GeForce 6200, Athlon XP 2400+ 32 bits processor) it works well with the proprietary NVIDIA driver. It does also somewhat work with the Nouveau driver but the first 10 lines of the screen are garbled after a page flipping, I must switch and go back from the console (Ctrl-F1 then Ctrl-F7) to get back a normal display. I hope it's only related to an outdated version of Nouveau (the one from Debian/unstable).

If it does work on a good range of NVIDIA GPUs I may be tempted to continue my work on my Genlock modification and my glstereo driver to implement a functional S3D driver for 120Hz displays under Linux.

Feel free to test it and to report back if it does work for you, giving your CPU, GPU and driver (NVIDIA or Nouveau) references.

Thank you.
User avatar
cybereality
3D Angel Eyes (Moderator)
Posts: 11407
Joined: Sat Apr 12, 2008 8:18 pm

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by cybereality »

Great work man! This sounds really good. Unfortunately I don't have a Linux machine setup currently, but I would love to test this myself. Been really wanting to test out the new version of Ubuntu, so I may try this at some point in the future.
mickeyjaw
Cross Eyed!
Posts: 131
Joined: Sun Feb 15, 2009 12:50 pm

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by mickeyjaw »

Tried it on ubuntu 10.04, nvidia proprietary 195.36.24, geforce 7900gtx

Doesn't appear to work - it says 'Page 1' and 'Page 2' but no viewport change occurs. Tried both outputs on the card, single monitor mode, dual monitor mode...
User avatar
Fredz
Petrif-Eyed
Posts: 2255
Joined: Sat Jan 09, 2010 2:06 pm
Location: Perpignan, France
Contact:

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by Fredz »

Did the previous version used in the modified Genlock work with your GPU ? You can also try these other versions if it was not the case :
http://askyl.blog.free.fr/index.php?pos ... ux-%282%29
http://askyl.blog.free.fr/index.php?pos ... -NVIDIA%29
http://askyl.blog.free.fr/index.php?pos ... ux-%283%29
http://askyl.blog.free.fr/index.php?pos ... ux-%284%29

It should work up to NV40 generation (including the 7900GTX). If it's not the case it may be because you have more than one display connected to your graphics card. It won't work on NV50+ hardware anyway, several people tested these versions with their NV50+ GPUs without success.

Nice to see you again mickeyjaw btw. :)
mickeyjaw
Cross Eyed!
Posts: 131
Joined: Sun Feb 15, 2009 12:50 pm

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by mickeyjaw »

Ok, so pflip-vga.c works, but none of the others do...
User avatar
Fredz
Petrif-Eyed
Posts: 2255
Joined: Sat Jan 09, 2010 2:06 pm
Location: Perpignan, France
Contact:

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by Fredz »

Do you use Nouveau or the NVIDIA binary driver ?
mickeyjaw
Cross Eyed!
Posts: 131
Joined: Sun Feb 15, 2009 12:50 pm

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by mickeyjaw »

Binary driver version 195.36.24
User avatar
Fredz
Petrif-Eyed
Posts: 2255
Joined: Sat Jan 09, 2010 2:06 pm
Location: Perpignan, France
Contact:

Re: Hardware page flipping on NVIDIA video cards under Linux

Post by Fredz »

Weird, all the versions of these pageflip tests did work with my GPU (6600GT). Anyway as I said it didn't work on any card >= NV50 so I've pretty much lot interest in this technique.

I've bought a new machine with an integrated Intel GPU, so I'll probably try to update glstereo for this hardware instead.
Post Reply

Return to “Do it Yourself!”