Merge branch 'master' of git+ssh://znh@git.freedesktop.org/git/mesa/mesa
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_buffers.c
1 #include "utils.h"
2 #include "framebuffer.h"
3 #include "renderbuffer.h"
4 #include "fbobject.h"
5
6 #include "nouveau_context.h"
7 #include "nouveau_buffers.h"
8 #include "nouveau_object.h"
9 #include "nouveau_fifo.h"
10 #include "nouveau_reg.h"
11 #include "nouveau_msg.h"
12
13 #define MAX_MEMFMT_LENGTH 32768
14
15 /* Unstrided blit using NV_MEMORY_TO_MEMORY_FORMAT */
16 GLboolean
17 nouveau_memformat_flat_emit(GLcontext *ctx,
18 nouveau_mem *dst, nouveau_mem *src,
19 GLuint dst_offset, GLuint src_offset,
20 GLuint size)
21 {
22 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
23 uint32_t src_handle, dst_handle;
24 GLuint count;
25
26 if (src_offset + size > src->size) {
27 MESSAGE("src out of nouveau_mem bounds\n");
28 return GL_FALSE;
29 }
30 if (dst_offset + size > dst->size) {
31 MESSAGE("dst out of nouveau_mem bounds\n");
32 return GL_FALSE;
33 }
34
35 src_handle = (src->type & NOUVEAU_MEM_FB) ? NvDmaFB : NvDmaAGP;
36 dst_handle = (dst->type & NOUVEAU_MEM_FB) ? NvDmaFB : NvDmaAGP;
37 src_offset += nouveau_mem_gpu_offset_get(ctx, src);
38 dst_offset += nouveau_mem_gpu_offset_get(ctx, dst);
39
40 BEGIN_RING_SIZE(NvSubMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_OBJECT_IN, 2);
41 OUT_RING (src_handle);
42 OUT_RING (dst_handle);
43
44 count = (size / MAX_MEMFMT_LENGTH) + ((size % MAX_MEMFMT_LENGTH) ? 1 : 0);
45
46 while (count--) {
47 GLuint length = (size > MAX_MEMFMT_LENGTH) ? MAX_MEMFMT_LENGTH : size;
48
49 BEGIN_RING_SIZE(NvSubMemFormat, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
50 OUT_RING (src_offset);
51 OUT_RING (dst_offset);
52 OUT_RING (0); /* pitch in */
53 OUT_RING (0); /* pitch out */
54 OUT_RING (length); /* line length */
55 OUT_RING (1); /* number of lines */
56 OUT_RING ((1 << 8) /* dst_inc */ | (1 << 0) /* src_inc */);
57 OUT_RING (0); /* buffer notify? */
58 FIRE_RING();
59
60 src_offset += length;
61 dst_offset += length;
62 size -= length;
63 }
64
65 return GL_TRUE;
66 }
67
68 void
69 nouveau_mem_free(GLcontext *ctx, nouveau_mem *mem)
70 {
71 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
72 drm_nouveau_mem_free_t memf;
73
74 if (NOUVEAU_DEBUG & DEBUG_MEM) {
75 fprintf(stderr, "%s: type=0x%x, offset=0x%x, size=0x%x\n",
76 __func__, mem->type, (GLuint)mem->offset, (GLuint)mem->size);
77 }
78
79 if (mem->map)
80 drmUnmap(mem->map, mem->size);
81 memf.flags = mem->type;
82 memf.region_offset = mem->offset;
83 drmCommandWrite(nmesa->driFd, DRM_NOUVEAU_MEM_FREE, &memf, sizeof(memf));
84 FREE(mem);
85 }
86
87 nouveau_mem *
88 nouveau_mem_alloc(GLcontext *ctx, int type, GLuint size, GLuint align)
89 {
90 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
91 drm_nouveau_mem_alloc_t mema;
92 nouveau_mem *mem;
93 int ret;
94
95 if (NOUVEAU_DEBUG & DEBUG_MEM) {
96 fprintf(stderr, "%s: requested: type=0x%x, size=0x%x, align=0x%x\n",
97 __func__, type, (GLuint)size, align);
98 }
99
100 mem = CALLOC(sizeof(nouveau_mem));
101 if (!mem)
102 return NULL;
103
104 mema.flags = type;
105 mema.size = mem->size = size;
106 mema.alignment = align;
107 mem->map = NULL;
108 ret = drmCommandWriteRead(nmesa->driFd, DRM_NOUVEAU_MEM_ALLOC,
109 &mema, sizeof(mema));
110 if (ret) {
111 FREE(mem);
112 return NULL;
113 }
114 mem->offset = mema.region_offset;
115 mem->type = mema.flags;
116
117 if (NOUVEAU_DEBUG & DEBUG_MEM) {
118 fprintf(stderr, "%s: actual: type=0x%x, offset=0x%x, size=0x%x\n",
119 __func__, mem->type, (GLuint)mem->offset, (GLuint)mem->size);
120 }
121
122 if (type & NOUVEAU_MEM_MAPPED)
123 ret = drmMap(nmesa->driFd, mem->offset, mem->size, &mem->map);
124 if (ret) {
125 mem->map = NULL;
126 nouveau_mem_free(ctx, mem);
127 mem = NULL;
128 }
129
130 return mem;
131 }
132
133 uint32_t
134 nouveau_mem_gpu_offset_get(GLcontext *ctx, nouveau_mem *mem)
135 {
136 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
137
138 if (mem->type & NOUVEAU_MEM_FB)
139 return (uint32_t)mem->offset - nmesa->vram_phys;
140 else if (mem->type & NOUVEAU_MEM_AGP)
141 return (uint32_t)mem->offset - nmesa->agp_phys;
142 else
143 return 0xDEADF00D;
144 }
145
146 static GLboolean
147 nouveau_renderbuffer_pixelformat(nouveau_renderbuffer *nrb,
148 GLenum internalFormat)
149 {
150 nrb->mesa.InternalFormat = internalFormat;
151
152 /*TODO: We probably want to extend this a bit, and maybe make
153 * card-specific?
154 */
155 switch (internalFormat) {
156 case GL_RGBA:
157 case GL_RGBA8:
158 nrb->mesa._BaseFormat = GL_RGBA;
159 nrb->mesa._ActualFormat= GL_RGBA8;
160 nrb->mesa.DataType = GL_UNSIGNED_BYTE;
161 nrb->mesa.RedBits = 8;
162 nrb->mesa.GreenBits = 8;
163 nrb->mesa.BlueBits = 8;
164 nrb->mesa.AlphaBits = 8;
165 nrb->cpp = 4;
166 break;
167 case GL_RGB:
168 case GL_RGB5:
169 nrb->mesa._BaseFormat = GL_RGB;
170 nrb->mesa._ActualFormat= GL_RGB5;
171 nrb->mesa.DataType = GL_UNSIGNED_BYTE;
172 nrb->mesa.RedBits = 5;
173 nrb->mesa.GreenBits = 6;
174 nrb->mesa.BlueBits = 5;
175 nrb->mesa.AlphaBits = 0;
176 nrb->cpp = 2;
177 break;
178 case GL_DEPTH_COMPONENT16:
179 nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
180 nrb->mesa._ActualFormat= GL_DEPTH_COMPONENT16;
181 nrb->mesa.DataType = GL_UNSIGNED_SHORT;
182 nrb->mesa.DepthBits = 16;
183 nrb->cpp = 2;
184 break;
185 case GL_DEPTH_COMPONENT24:
186 nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
187 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
188 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
189 nrb->mesa.DepthBits = 24;
190 nrb->cpp = 4;
191 break;
192 case GL_STENCIL_INDEX8_EXT:
193 nrb->mesa._BaseFormat = GL_STENCIL_INDEX;
194 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
195 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
196 nrb->mesa.StencilBits = 8;
197 nrb->cpp = 4;
198 break;
199 case GL_DEPTH24_STENCIL8_EXT:
200 nrb->mesa._BaseFormat = GL_DEPTH_STENCIL_EXT;
201 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
202 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
203 nrb->mesa.DepthBits = 24;
204 nrb->mesa.StencilBits = 8;
205 nrb->cpp = 4;
206 break;
207 default:
208 return GL_FALSE;
209 break;
210 }
211
212 return GL_TRUE;
213 }
214
215 static GLboolean
216 nouveau_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
217 GLenum internalFormat,
218 GLuint width,
219 GLuint height)
220 {
221 nouveau_renderbuffer *nrb = (nouveau_renderbuffer*)rb;
222
223 if (!nouveau_renderbuffer_pixelformat(nrb, internalFormat)) {
224 fprintf(stderr, "%s: unknown internalFormat\n", __func__);
225 return GL_FALSE;
226 }
227
228 /* If this buffer isn't statically alloc'd, we may need to ask the
229 * drm for more memory */
230 if (!nrb->dPriv && (rb->Width != width || rb->Height != height)) {
231 GLuint pitch;
232
233 /* align pitches to 64 bytes */
234 pitch = ((width * nrb->cpp) + 63) & ~63;
235
236 if (nrb->mem)
237 nouveau_mem_free(ctx, nrb->mem);
238 nrb->mem = nouveau_mem_alloc(ctx,
239 NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
240 pitch*height,
241 0);
242 if (!nrb->mem)
243 return GL_FALSE;
244
245 /* update nouveau_renderbuffer info */
246 nrb->offset = nouveau_mem_gpu_offset_get(ctx, nrb->mem);
247 nrb->pitch = pitch;
248 }
249
250 rb->Width = width;
251 rb->Height = height;
252 rb->InternalFormat = internalFormat;
253 return GL_TRUE;
254 }
255
256 static void
257 nouveau_renderbuffer_delete(struct gl_renderbuffer *rb)
258 {
259 GET_CURRENT_CONTEXT(ctx);
260 nouveau_renderbuffer *nrb = (nouveau_renderbuffer*)rb;
261
262 if (nrb->mem)
263 nouveau_mem_free(ctx, nrb->mem);
264 FREE(nrb);
265 }
266
267 nouveau_renderbuffer *
268 nouveau_renderbuffer_new(GLenum internalFormat, GLvoid *map,
269 GLuint offset, GLuint pitch,
270 __DRIdrawablePrivate *dPriv)
271 {
272 nouveau_renderbuffer *nrb;
273
274 nrb = CALLOC_STRUCT(nouveau_renderbuffer_t);
275 if (nrb) {
276 _mesa_init_renderbuffer(&nrb->mesa, 0);
277
278 nouveau_renderbuffer_pixelformat(nrb, internalFormat);
279
280 nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
281 nrb->mesa.Delete = nouveau_renderbuffer_delete;
282
283 nrb->dPriv = dPriv;
284 nrb->offset = offset;
285 nrb->pitch = pitch;
286 nrb->map = map;
287 }
288
289 return nrb;
290 }
291
292 static void
293 nouveau_cliprects_drawable_set(nouveauContextPtr nmesa,
294 nouveau_renderbuffer *nrb)
295 {
296 __DRIdrawablePrivate *dPriv = nrb->dPriv;
297
298 nmesa->numClipRects = dPriv->numClipRects;
299 nmesa->pClipRects = dPriv->pClipRects;
300 nmesa->drawX = dPriv->x;
301 nmesa->drawY = dPriv->y;
302 }
303
304 static void
305 nouveau_cliprects_renderbuffer_set(nouveauContextPtr nmesa,
306 nouveau_renderbuffer *nrb)
307 {
308 nmesa->numClipRects = 1;
309 nmesa->pClipRects = &nmesa->osClipRect;
310 nmesa->osClipRect.x1 = 0;
311 nmesa->osClipRect.y1 = 0;
312 nmesa->osClipRect.x2 = nrb->mesa.Width;
313 nmesa->osClipRect.y2 = nrb->mesa.Height;
314 nmesa->drawX = 0;
315 nmesa->drawY = 0;
316 }
317
318 void
319 nouveau_window_moved(GLcontext *ctx)
320 {
321 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
322 nouveau_renderbuffer *nrb;
323
324 nrb = (nouveau_renderbuffer *)ctx->DrawBuffer->_ColorDrawBuffers[0][0];
325 if (!nrb)
326 return;
327
328 if (!nrb->dPriv)
329 nouveau_cliprects_renderbuffer_set(nmesa, nrb);
330 else
331 nouveau_cliprects_drawable_set(nmesa, nrb);
332
333 /* Viewport depends on window size/position, nouveauCalcViewport
334 * will take care of calling the hw-specific WindowMoved
335 */
336 ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
337 ctx->Viewport.Width, ctx->Viewport.Height);
338 /* Scissor depends on window position */
339 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
340 ctx->Scissor.Width, ctx->Scissor.Height);
341 }
342
343 GLboolean
344 nouveau_build_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
345 {
346 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
347 nouveau_renderbuffer *color[MAX_DRAW_BUFFERS];
348 nouveau_renderbuffer *depth;
349
350 _mesa_update_framebuffer(ctx);
351 _mesa_update_draw_buffer_bounds(ctx);
352
353 color[0] = (nouveau_renderbuffer *)fb->_ColorDrawBuffers[0][0];
354 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped)
355 depth = (nouveau_renderbuffer *)fb->_DepthBuffer->Wrapped;
356 else
357 depth = (nouveau_renderbuffer *)fb->_DepthBuffer;
358
359 if (!nmesa->hw_func.BindBuffers(nmesa, 1, color, depth))
360 return GL_FALSE;
361 nouveau_window_moved(ctx);
362
363 return GL_TRUE;
364 }
365
366 static void
367 nouveauDrawBuffer(GLcontext *ctx, GLenum buffer)
368 {
369 nouveau_build_framebuffer(ctx, ctx->DrawBuffer);
370 }
371
372 static struct gl_framebuffer *
373 nouveauNewFramebuffer(GLcontext *ctx, GLuint name)
374 {
375 return _mesa_new_framebuffer(ctx, name);
376 }
377
378 static struct gl_renderbuffer *
379 nouveauNewRenderbuffer(GLcontext *ctx, GLuint name)
380 {
381 nouveau_renderbuffer *nrb;
382
383 nrb = CALLOC_STRUCT(nouveau_renderbuffer_t);
384 if (nrb) {
385 _mesa_init_renderbuffer(&nrb->mesa, name);
386
387 nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
388 nrb->mesa.Delete = nouveau_renderbuffer_delete;
389 }
390 return &nrb->mesa;
391 }
392
393 static void
394 nouveauBindFramebuffer(GLcontext *ctx, GLenum target, struct gl_framebuffer *fb)
395 {
396 nouveau_build_framebuffer(ctx, fb);
397 }
398
399 static void
400 nouveauFramebufferRenderbuffer(GLcontext *ctx,
401 struct gl_framebuffer *fb,
402 GLenum attachment,
403 struct gl_renderbuffer *rb)
404 {
405 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
406 nouveau_build_framebuffer(ctx, fb);
407 }
408
409 static void
410 nouveauRenderTexture(GLcontext *ctx,
411 struct gl_framebuffer *fb,
412 struct gl_renderbuffer_attachment *att)
413 {
414 }
415
416 static void
417 nouveauFinishRenderTexture(GLcontext *ctx,
418 struct gl_renderbuffer_attachment *att)
419 {
420 }
421
422 void
423 nouveauInitBufferFuncs(struct dd_function_table *func)
424 {
425 func->DrawBuffer = nouveauDrawBuffer;
426
427 func->NewFramebuffer = nouveauNewFramebuffer;
428 func->NewRenderbuffer = nouveauNewRenderbuffer;
429 func->BindFramebuffer = nouveauBindFramebuffer;
430 func->FramebufferRenderbuffer = nouveauFramebufferRenderbuffer;
431 func->RenderTexture = nouveauRenderTexture;
432 func->FinishRenderTexture = nouveauFinishRenderTexture;
433 }
434