All pastes #1518824 Raw Edit

Someone

public text v1 · immutable
#1518824 ·published 2009-08-05 06:02 UTC
rendered paste body
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <xf86drm.h>
#include "nouveau_drm.h"
#include "nouveau_device.h"
#include "nouveau_notifier.h"
#include "nouveau_channel.h"
#include "nouveau_pushbuf.h"
#include "nouveau_bo.h"
#include "nouveau_class.h"

#define NvDmaFB 0xD0FB0001
#define NvDmaTT 0xD0AA0001
#define Nv2D 0xD02D0001
#define NvM2MF 0xD02D0002
#define NvNotify 0xD0000001

struct nouveau_device *dev = NULL;
struct nouveau_channel *chan = NULL;
struct nouveau_notifier *notifier = NULL;
struct nouveau_grobj *eng2d = NULL;
struct nouveau_grobj *m2mf = NULL;
struct nouveau_bo *bo = NULL;
struct nouveau_bo *gart = NULL;

#define NV84_MODE 0
#define NV90_MODE 0

#define WIDTH 400
#define HEIGHT 400
#define TILING_PARAM 0x40

#if TILING_PARAM == 0x00
#define TILE_WIDTH 64
#define TILE_HEIGHT 4
#elif TILING_PARAM == 0x10
#define TILE_WIDTH 64
#define TILE_HEIGHT 8
#elif TILING_PARAM == 0x20
#define TILE_WIDTH 64
#define TILE_HEIGHT 16
#elif TILING_PARAM == 0x30
#define TILE_WIDTH 64
#define TILE_HEIGHT 32
#elif TILING_PARAM == 0x40
#define TILE_WIDTH 64
#define TILE_HEIGHT 64
#endif

#define PITCH_WIDTH ((WIDTH + 63) & ~63)
#define PITCH_HEIGHT ((HEIGHT + TILE_HEIGHT - 1) & ~(TILE_HEIGHT - 1))

void
get_dst()
{
	int ret = 0, i;
	uint8_t *map;

	if (ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_TILED | NOUVEAU_BO_MAP, 256, PITCH_WIDTH*PITCH_HEIGHT + 65536, &bo)) {
		fprintf(stderr, "nouveau_bo_new failed with %d\n", ret);
		return;
	}

	/* Set destination. */
	BEGIN_RING (chan, eng2d, NV50_2D_DST_FORMAT, 5);
	OUT_RING (chan, NV50_2D_DST_FORMAT_R8_UNORM);
	OUT_RING (chan, 0);
	OUT_RING (chan, TILING_PARAM);
	OUT_RING  (chan, 1);
	OUT_RING  (chan, 0);

	BEGIN_RING (chan, eng2d, NV50_2D_DST_WIDTH, 4);
	OUT_RING (chan, WIDTH);
	OUT_RING (chan, HEIGHT);
	OUT_RELOCh(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
	OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);

	BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4);
	OUT_RING  (chan, 0);
	OUT_RING  (chan, 0);
	OUT_RING  (chan, WIDTH);
	OUT_RING  (chan, HEIGHT);

	BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
	OUT_RING  (chan, NV50_2D_OPERATION_SRCCOPY);

	FIRE_RING  (chan);

	/* clear the pixmap */
	nouveau_bo_map(bo, NOUVEAU_BO_RDWR);
	map = bo->map;
	if (!map) {
		fprintf(stderr, "map failed\n");
		return;
	}

	for (i = 0; i < bo->size; i++)
		map[i] = 0x00;

	nouveau_bo_unmap(bo);
}

void
get_gart()
{
	int ret;

	if (ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 256, PITCH_WIDTH*PITCH_HEIGHT + 65536, &gart)) {
		fprintf(stderr, "nouveau_bo_new failed with %d\n", ret);
		return;
	}
}

int
recurse_offset(int tile_height, int x, int y, int pitch)
{
	int tile_width = TILE_WIDTH;
	int offset;

	offset = ((x/tile_width) + (y/tile_height) * (pitch/tile_width)) * (tile_height *  tile_width);
	offset += (y % tile_height) * tile_width + (x % tile_width);

	return offset;
}

void download_pixels(int x, int y, int full)
{
	unsigned line_len;
	unsigned line_count;
	unsigned offset;
	uint64_t vram_offset = 0;

	if (full) {
		offset = 0;
		line_len = PITCH_WIDTH;
		line_count = PITCH_HEIGHT;
	} else {
		offset = recurse_offset(TILE_HEIGHT, x, y, PITCH_WIDTH);
		line_len = 1;
		line_count = 1;
	}

	nouveau_bo_pin(bo, NOUVEAU_BO_VRAM);
	if (!bo->offset) {
		fprintf(stderr, "no offset\n");
		exit(0);
	}
	vram_offset = bo->offset - dev->vm_vram_base;
	fprintf(stderr, "0x%016llx\n", vram_offset);

	WAIT_RING (chan, 32);
	BEGIN_RING(chan, m2mf, 0x180, 3);
	OUT_RING (chan, notifier->handle);
	OUT_RING (chan, 0xdeadcafe);
	OUT_RELOCo(chan, gart, NOUVEAU_BO_GART | NOUVEAU_BO_WR);

	BEGIN_RING(chan, m2mf, 0x0200, 1);
	OUT_RING  (chan, 1);

	BEGIN_RING(chan, m2mf, 0x021c, 1);
	OUT_RING  (chan, 1);

	BEGIN_RING(chan, m2mf, 0x238, 2);
	OUT_RING(chan, vram_offset >> 32);
	OUT_RELOCh(chan, gart, offset, NOUVEAU_BO_GART | NOUVEAU_BO_WR);

	BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
	OUT_RING(chan, vram_offset & 0xFFFFFFFF);
	OUT_RELOCl(chan, gart, offset, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
	OUT_RING  (chan, PITCH_WIDTH);
	OUT_RING  (chan, PITCH_WIDTH);
	OUT_RING  (chan, line_len);
	OUT_RING  (chan, line_count);
	OUT_RING  (chan, (1<<8)|1);
	OUT_RING  (chan, 0);

	FIRE_RING (chan);

	nouveau_bo_unpin(bo);
}

void
set_pixel(int x, int y, uint32_t pixel)
{
	BEGIN_RING (chan, eng2d, NV50_2D_DST_ADDRESS_HIGH, 2);
	OUT_RELOCh(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
	OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);

	BEGIN_RING(chan, eng2d, 0x580, 3);
	OUT_RING  (chan, 4);
	OUT_RING  (chan, NV50_2D_RECT_FORMAT_R8_UNORM);
	OUT_RING  (chan, pixel);

	BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4);
	OUT_RING  (chan, x);
	OUT_RING  (chan, y);
	OUT_RING  (chan, x + 1);
	OUT_RING  (chan, y + 1);

	FIRE_RING (chan);
}

void
find_pixel (int x, int y, int *offset, uint32_t pixel)
{
	uint8_t *map = NULL;
	int smart_offset = *offset - 2048;
	int smart_end = smart_offset + 4096;

	if (smart_offset < 0)
		smart_offset = 0;
	if (smart_end > gart->size)
		smart_end = gart->size;

	if (x == 0)
		fprintf(stderr, "y% d\n", y);

	download_pixels(x, y, 0);

	nouveau_bo_map(gart, NOUVEAU_BO_RDWR);
	map = gart->map;
	if (!map) {
		fprintf(stderr, "map failed\n");
		exit(0);
	};

	if (map[*offset] == (pixel & 0xFF))
		goto out;

	fprintf(stderr, "fail\n");

	nouveau_bo_unmap(gart);

	download_pixels(x, y, 1);

	nouveau_bo_map(gart, NOUVEAU_BO_RDWR);
	map = gart->map;
	if (!map) {
		fprintf(stdout, "map failed\n");
		exit(0);
	};

	for ((*offset) = smart_offset; (*offset) < smart_end; (*offset)++)
		if ((map[(*offset)]) == ((pixel) & 0xFF))
			goto out;

	for ((*offset) = 0; (*offset) < gart->size; (*offset)++)
		if ((map[(*offset)]) == ((pixel) & 0xFF))
			goto out;

	fprintf(stderr, "really fail\n");
out:
	nouveau_bo_unmap(gart);
}

int
main(int argc, char **argv)
{
	int ret = 0;
	int x = 0, y = 0;
	int offset = 0, offset_expected = 0;

	if (ret = nouveau_device_open(&dev, NULL)) {
		fprintf(stderr, "nouveau_device_open failed\n");
		return ret;
	}

	if (ret = nouveau_channel_alloc(dev, NvDmaFB, NvDmaTT, &chan)) {
		fprintf(stderr, "nouveau_channel_alloc failed\n");
		return ret;
	}

	if (ret = nouveau_notifier_alloc(chan, NvNotify, 1, &notifier)) {
		fprintf(stderr, "nouveau_notifier_alloc failed\n");
		return ret;
	}

	/* 2D object */
	if (ret = nouveau_grobj_alloc(chan, Nv2D, 0x502d, &eng2d)) {
		fprintf(stderr, "nouveau_grobj_alloc failed\n");
		return ret;
	}

	if (ret = nouveau_grobj_alloc(chan, NvM2MF, NV50_MEMORY_TO_MEMORY_FORMAT, &m2mf)) {
		fprintf(stderr, "nouveau_grobj_alloc failed\n");
		return ret;
	}

	BEGIN_RING (chan, eng2d, 0x180, 3);
	OUT_RING  (chan, notifier->handle);
	OUT_RING  (chan, chan->vram->handle);
	OUT_RING  (chan, chan->gart->handle);

	/* Magics from nv, no clue what they do, but at least some
	 * of them are needed to avoid crashes.
	 */
	BEGIN_RING(chan, eng2d, 0x260, 1);
	OUT_RING  (chan, 1);
	BEGIN_RING(chan, eng2d, 0x290, 1);
	OUT_RING  (chan, 1);
	BEGIN_RING(chan, eng2d, 0x29c, 1);
	OUT_RING  (chan, 0);
	BEGIN_RING(chan, eng2d, 0x58c, 1);
	OUT_RING  (chan, 0x111);

	/* Now we are ready for the real stuff. */
	get_dst();
	if (!bo) {
		fprintf(stderr, "get_dst failed\n");
		return -ENOMEM;
	}
	get_gart();
	if (!gart) {
		fprintf(stderr, "get_gart failed\n");
		return -ENOMEM;
	}

	for (y = 0; y < HEIGHT; y++) {
		for (x = 0; x < WIDTH; x++) {
			set_pixel(x, y, 0xFFFFFFFF);
			offset_expected = recurse_offset(TILE_HEIGHT, x, y, PITCH_WIDTH);
			offset = offset_expected;
			find_pixel(x, y, &offset, 0xFFFFFFFF);
			set_pixel(x, y, 0x0);
			if (offset_expected != offset) {
				printf("offset %d offset_expected %d diff %d \n", offset, offset_expected, offset_expected - offset);
				printf("x %d y %d\n", x, y);
			}
		}
	}

	nouveau_device_close(&dev);

	return ret;
}