summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/nouveau/nouveau_mem.c
blob: 35c53268b0610ec88a587559eabf16c1556cc9de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "mtypes.h"

#include "nouveau_context.h"
#include "nouveau_fifo.h"
#include "nouveau_mem.h"
#include "nouveau_msg.h"
#include "nouveau_object.h"
#include "nouveau_reg.h"

#define MAX_MEMFMT_LENGTH 32768

/* Unstrided blit using NV_MEMORY_TO_MEMORY_FORMAT */
GLboolean
nouveau_memformat_flat_emit(GLcontext * ctx,
			    nouveau_mem * dst, nouveau_mem * src,
			    GLuint dst_offset, GLuint src_offset,
			    GLuint size)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
	uint32_t src_handle, dst_handle;
	GLuint count;

	if (src_offset + size > src->size) {
		MESSAGE("src out of nouveau_mem bounds\n");
		return GL_FALSE;
	}
	if (dst_offset + size > dst->size) {
		MESSAGE("dst out of nouveau_mem bounds\n");
		return GL_FALSE;
	}

	src_handle = (src->type & NOUVEAU_MEM_FB) ? NvDmaFB : NvDmaTT;
	dst_handle = (dst->type & NOUVEAU_MEM_FB) ? NvDmaFB : NvDmaTT;
	src_offset += nouveau_mem_gpu_offset_get(ctx, src);
	dst_offset += nouveau_mem_gpu_offset_get(ctx, dst);

	BEGIN_RING_SIZE(NvSubMemFormat,
			NV_MEMORY_TO_MEMORY_FORMAT_OBJECT_IN, 2);
	OUT_RING(src_handle);
	OUT_RING(dst_handle);

	count = (size / MAX_MEMFMT_LENGTH) + 
		((size % MAX_MEMFMT_LENGTH) ? 1 : 0);

	while (count--) {
		GLuint length =
		    (size > MAX_MEMFMT_LENGTH) ? MAX_MEMFMT_LENGTH : size;

		BEGIN_RING_SIZE(NvSubMemFormat,
				NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
		OUT_RING(src_offset);
		OUT_RING(dst_offset);
		OUT_RING(0);	/* pitch in */
		OUT_RING(0);	/* pitch out */
		OUT_RING(length);	/* line length */
		OUT_RING(1);	/* number of lines */
		OUT_RING((1 << 8) /* dst_inc */ |(1 << 0) /* src_inc */ );
		OUT_RING(0);	/* buffer notify? */
		FIRE_RING();

		src_offset += length;
		dst_offset += length;
		size -= length;
	}

	return GL_TRUE;
}

void nouveau_mem_free(GLcontext * ctx, nouveau_mem * mem)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
	struct drm_nouveau_mem_free memf;

	if (NOUVEAU_DEBUG & DEBUG_MEM) {
		fprintf(stderr, "%s: type=0x%x, offset=0x%x, size=0x%x\n",
			__func__, mem->type, (GLuint) mem->offset,
			(GLuint) mem->size);
	}

	if (mem->map)
		drmUnmap(mem->map, mem->size);
	memf.flags = mem->type;
	memf.offset = mem->offset;
	drmCommandWrite(nmesa->driFd, DRM_NOUVEAU_MEM_FREE, &memf,
			sizeof(memf));
	FREE(mem);
}

nouveau_mem *nouveau_mem_alloc(GLcontext *ctx, uint32_t flags, GLuint size,
			       GLuint align)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
	struct drm_nouveau_mem_alloc mema;
	nouveau_mem *mem;
	int ret;

	if (NOUVEAU_DEBUG & DEBUG_MEM) {
		fprintf(stderr,
			"%s: requested: flags=0x%x, size=0x%x, align=0x%x\n",
			__func__, flags, (GLuint) size, align);
	}

	mem = CALLOC(sizeof(nouveau_mem));
	if (!mem)
		return NULL;

	mema.flags = flags;
	mema.size = mem->size = size;
	mema.alignment = align;
	mem->map = NULL;
	ret = drmCommandWriteRead(nmesa->driFd, DRM_NOUVEAU_MEM_ALLOC,
				  &mema, sizeof(mema));
	if (ret) {
		FREE(mem);
		return NULL;
	}
	mem->offset = mema.offset;
	mem->type = mema.flags;

	if (NOUVEAU_DEBUG & DEBUG_MEM) {
		fprintf(stderr,
			"%s: actual: type=0x%x, offset=0x%x, size=0x%x\n",
			__func__, mem->type, (GLuint) mem->offset,
			(GLuint) mem->size);
	}

	if (flags & NOUVEAU_MEM_MAPPED)
		ret = drmMap(nmesa->driFd, mema.map_handle, mem->size,
			     &mem->map);
	if (ret) {
		mem->map = NULL;
		nouveau_mem_free(ctx, mem);
		mem = NULL;
	}

	return mem;
}

uint32_t nouveau_mem_gpu_offset_get(GLcontext * ctx, nouveau_mem * mem)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);

	return mem->offset;
}