Merge branch 'master' of git+ssh://znh@git.freedesktop.org/git/mesa/mesa into 965...
[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 : NvDmaTT;
36 dst_handle = (dst->type & NOUVEAU_MEM_FB) ? NvDmaFB : NvDmaTT;
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 struct drm_nouveau_mem_free 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.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 struct drm_nouveau_mem_alloc 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.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, mema.map_handle, 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 return mem->offset;
139 }
140
141 static GLboolean
142 nouveau_renderbuffer_pixelformat(nouveau_renderbuffer *nrb,
143 GLenum internalFormat)
144 {
145 nrb->mesa.InternalFormat = internalFormat;
146
147 /*TODO: We probably want to extend this a bit, and maybe make
148 * card-specific?
149 */
150 switch (internalFormat) {
151 case GL_RGBA:
152 case GL_RGBA8:
153 nrb->mesa._BaseFormat = GL_RGBA;
154 nrb->mesa._ActualFormat= GL_RGBA8;
155 nrb->mesa.DataType = GL_UNSIGNED_BYTE;
156 nrb->mesa.RedBits = 8;
157 nrb->mesa.GreenBits = 8;
158 nrb->mesa.BlueBits = 8;
159 nrb->mesa.AlphaBits = 8;
160 nrb->cpp = 4;
161 break;
162 case GL_RGB:
163 case GL_RGB5:
164 nrb->mesa._BaseFormat = GL_RGB;
165 nrb->mesa._ActualFormat= GL_RGB5;
166 nrb->mesa.DataType = GL_UNSIGNED_BYTE;
167 nrb->mesa.RedBits = 5;
168 nrb->mesa.GreenBits = 6;
169 nrb->mesa.BlueBits = 5;
170 nrb->mesa.AlphaBits = 0;
171 nrb->cpp = 2;
172 break;
173 case GL_DEPTH_COMPONENT16:
174 nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
175 nrb->mesa._ActualFormat= GL_DEPTH_COMPONENT16;
176 nrb->mesa.DataType = GL_UNSIGNED_SHORT;
177 nrb->mesa.DepthBits = 16;
178 nrb->cpp = 2;
179 break;
180 case GL_DEPTH_COMPONENT24:
181 nrb->mesa._BaseFormat = GL_DEPTH_COMPONENT;
182 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
183 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
184 nrb->mesa.DepthBits = 24;
185 nrb->cpp = 4;
186 break;
187 case GL_STENCIL_INDEX8_EXT:
188 nrb->mesa._BaseFormat = GL_STENCIL_INDEX;
189 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
190 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
191 nrb->mesa.StencilBits = 8;
192 nrb->cpp = 4;
193 break;
194 case GL_DEPTH24_STENCIL8_EXT:
195 nrb->mesa._BaseFormat = GL_DEPTH_STENCIL_EXT;
196 nrb->mesa._ActualFormat= GL_DEPTH24_STENCIL8_EXT;
197 nrb->mesa.DataType = GL_UNSIGNED_INT_24_8_EXT;
198 nrb->mesa.DepthBits = 24;
199 nrb->mesa.StencilBits = 8;
200 nrb->cpp = 4;
201 break;
202 default:
203 return GL_FALSE;
204 break;
205 }
206
207 return GL_TRUE;
208 }
209
210 static GLboolean
211 nouveau_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
212 GLenum internalFormat,
213 GLuint width,
214 GLuint height)
215 {
216 nouveau_renderbuffer *nrb = (nouveau_renderbuffer*)rb;
217
218 if (!nouveau_renderbuffer_pixelformat(nrb, internalFormat)) {
219 fprintf(stderr, "%s: unknown internalFormat\n", __func__);
220 return GL_FALSE;
221 }
222
223 /* If this buffer isn't statically alloc'd, we may need to ask the
224 * drm for more memory */
225 if (!nrb->dPriv && (rb->Width != width || rb->Height != height)) {
226 GLuint pitch;
227
228 /* align pitches to 64 bytes */
229 pitch = ((width * nrb->cpp) + 63) & ~63;
230
231 if (nrb->mem)
232 nouveau_mem_free(ctx, nrb->mem);
233 nrb->mem = nouveau_mem_alloc(ctx,
234 NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
235 pitch*height,
236 0);
237 if (!nrb->mem)
238 return GL_FALSE;
239
240 /* update nouveau_renderbuffer info */
241 nrb->offset = nouveau_mem_gpu_offset_get(ctx, nrb->mem);
242 nrb->pitch = pitch;
243 }
244
245 rb->Width = width;
246 rb->Height = height;
247 rb->InternalFormat = internalFormat;
248 return GL_TRUE;
249 }
250
251 static void
252 nouveau_renderbuffer_delete(struct gl_renderbuffer *rb)
253 {
254 GET_CURRENT_CONTEXT(ctx);
255 nouveau_renderbuffer *nrb = (nouveau_renderbuffer*)rb;
256
257 if (nrb->mem)
258 nouveau_mem_free(ctx, nrb->mem);
259 FREE(nrb);
260 }
261
262 nouveau_renderbuffer *
263 nouveau_renderbuffer_new(GLenum internalFormat, GLvoid *map,
264 GLuint offset, GLuint pitch,
265 __DRIdrawablePrivate *dPriv)
266 {
267 nouveau_renderbuffer *nrb;
268
269 nrb = CALLOC_STRUCT(nouveau_renderbuffer_t);
270 if (nrb) {
271 _mesa_init_renderbuffer(&nrb->mesa, 0);
272
273 nouveau_renderbuffer_pixelformat(nrb, internalFormat);
274
275 nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
276 nrb->mesa.Delete = nouveau_renderbuffer_delete;
277
278 nrb->dPriv = dPriv;
279 nrb->offset = offset;
280 nrb->pitch = pitch;
281 nrb->map = map;
282 }
283
284 return nrb;
285 }
286
287 static void
288 nouveau_cliprects_drawable_set(nouveauContextPtr nmesa,
289 nouveau_renderbuffer *nrb)
290 {
291 __DRIdrawablePrivate *dPriv = nrb->dPriv;
292
293 nmesa->numClipRects = dPriv->numClipRects;
294 nmesa->pClipRects = dPriv->pClipRects;
295 nmesa->drawX = dPriv->x;
296 nmesa->drawY = dPriv->y;
297 nmesa->drawW = dPriv->w;
298 nmesa->drawH = dPriv->h;
299 }
300
301 static void
302 nouveau_cliprects_renderbuffer_set(nouveauContextPtr nmesa,
303 nouveau_renderbuffer *nrb)
304 {
305 nmesa->numClipRects = 1;
306 nmesa->pClipRects = &nmesa->osClipRect;
307 nmesa->osClipRect.x1 = 0;
308 nmesa->osClipRect.y1 = 0;
309 nmesa->osClipRect.x2 = nrb->mesa.Width;
310 nmesa->osClipRect.y2 = nrb->mesa.Height;
311 nmesa->drawX = 0;
312 nmesa->drawY = 0;
313 nmesa->drawW = nrb->mesa.Width;
314 nmesa->drawH = nrb->mesa.Height;
315 }
316
317 void
318 nouveau_window_moved(GLcontext *ctx)
319 {
320 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
321 nouveau_renderbuffer *nrb;
322
323 nrb = (nouveau_renderbuffer *)ctx->DrawBuffer->_ColorDrawBuffers[0][0];
324 if (!nrb)
325 return;
326
327 if (!nrb->dPriv)
328 nouveau_cliprects_renderbuffer_set(nmesa, nrb);
329 else
330 nouveau_cliprects_drawable_set(nmesa, nrb);
331
332 /* Viewport depends on window size/position, nouveauCalcViewport
333 * will take care of calling the hw-specific WindowMoved
334 */
335 ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
336 ctx->Viewport.Width, ctx->Viewport.Height);
337 /* Scissor depends on window position */
338 ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
339 ctx->Scissor.Width, ctx->Scissor.Height);
340 }
341
342 GLboolean
343 nouveau_build_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
344 {
345 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
346 nouveau_renderbuffer *color[MAX_DRAW_BUFFERS];
347 nouveau_renderbuffer *depth;
348
349 _mesa_update_framebuffer(ctx);
350 _mesa_update_draw_buffer_bounds(ctx);
351
352 color[0] = (nouveau_renderbuffer *)fb->_ColorDrawBuffers[0][0];
353 if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped)
354 depth = (nouveau_renderbuffer *)fb->_DepthBuffer->Wrapped;
355 else
356 depth = (nouveau_renderbuffer *)fb->_DepthBuffer;
357
358 if (!nmesa->hw_func.BindBuffers(nmesa, 1, color, depth))
359 return GL_FALSE;
360 nouveau_window_moved(ctx);
361
362 return GL_TRUE;
363 }
364
365 static void
366 nouveauDrawBuffer(GLcontext *ctx, GLenum buffer)
367 {
368 nouveau_build_framebuffer(ctx, ctx->DrawBuffer);
369 }
370
371 static struct gl_framebuffer *
372 nouveauNewFramebuffer(GLcontext *ctx, GLuint name)
373 {
374 return _mesa_new_framebuffer(ctx, name);
375 }
376
377 static struct gl_renderbuffer *
378 nouveauNewRenderbuffer(GLcontext *ctx, GLuint name)
379 {
380 nouveau_renderbuffer *nrb;
381
382 nrb = CALLOC_STRUCT(nouveau_renderbuffer_t);
383 if (nrb) {
384 _mesa_init_renderbuffer(&nrb->mesa, name);
385
386 nrb->mesa.AllocStorage = nouveau_renderbuffer_storage;
387 nrb->mesa.Delete = nouveau_renderbuffer_delete;
388 }
389 return &nrb->mesa;
390 }
391
392 static void
393 nouveauBindFramebuffer(GLcontext *ctx, GLenum target, struct gl_framebuffer *fb)
394 {
395 nouveau_build_framebuffer(ctx, fb);
396 }
397
398 static void
399 nouveauFramebufferRenderbuffer(GLcontext *ctx,
400 struct gl_framebuffer *fb,
401 GLenum attachment,
402 struct gl_renderbuffer *rb)
403 {
404 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
405 nouveau_build_framebuffer(ctx, fb);
406 }
407
408 static void
409 nouveauRenderTexture(GLcontext *ctx,
410 struct gl_framebuffer *fb,
411 struct gl_renderbuffer_attachment *att)
412 {
413 }
414
415 static void
416 nouveauFinishRenderTexture(GLcontext *ctx,
417 struct gl_renderbuffer_attachment *att)
418 {
419 }
420
421 void
422 nouveauInitBufferFuncs(struct dd_function_table *func)
423 {
424 func->DrawBuffer = nouveauDrawBuffer;
425
426 func->NewFramebuffer = nouveauNewFramebuffer;
427 func->NewRenderbuffer = nouveauNewRenderbuffer;
428 func->BindFramebuffer = nouveauBindFramebuffer;
429 func->FramebufferRenderbuffer = nouveauFramebufferRenderbuffer;
430 func->RenderTexture = nouveauRenderTexture;
431 func->FinishRenderTexture = nouveauFinishRenderTexture;
432 }
433