main nouveau.c
  1/* wld: nouveau.c
  2 *
  3 * Copyright (c) 2013, 2014 Michael Forney
  4 *
  5 * Based in part upon nvc0_exa.c from xf86-video-nouveau, which is:
  6 *
  7 *     Copyright 2007 NVIDIA, Corporation
  8 *     Copyright 2008 Ben Skeggs
  9 *
 10 * Permission is hereby granted, free of charge, to any person obtaining a copy
 11 * of this software and associated documentation files (the "Software"), to deal
 12 * in the Software without restriction, including without limitation the rights
 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14 * copies of the Software, and to permit persons to whom the Software is
 15 * furnished to do so, subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be included in
 18 * all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 26 * SOFTWARE.
 27 */
 28
 29#include "drm-private.h"
 30#include "drm.h"
 31#include "nouveau/g80_2d.xml.h"
 32#include "nouveau/g80_defs.xml.h"
 33#include "nouveau/nv_object.xml.h"
 34#include "pixman.h"
 35
 36#include <nouveau.h>
 37#include <string.h>
 38#include <sys/mman.h>
 39
 40enum nv_architecture {
 41	NV_ARCH_50 = 0x50,
 42	NV_ARCH_C0 = 0xc0,
 43	NV_ARCH_E0 = 0xe0
 44};
 45
 46struct nouveau_context {
 47	struct wld_context base;
 48	struct nouveau_device *device;
 49	struct nouveau_client *client;
 50	enum nv_architecture architecture;
 51};
 52
 53struct nouveau_renderer {
 54	struct wld_renderer base;
 55	struct nouveau_object *channel;
 56	struct nouveau_pushbuf *pushbuf;
 57	struct nouveau_bufctx *bufctx;
 58	struct nouveau_object *nvc0_2d;
 59
 60	struct nouveau_buffer *target;
 61};
 62
 63struct nouveau_buffer {
 64	struct buffer base;
 65	struct wld_exporter exporter;
 66	struct nouveau_context *context;
 67	struct nouveau_bo *bo;
 68};
 69
 70#include "interface/buffer.h"
 71#include "interface/context.h"
 72#include "interface/renderer.h"
 73#define DRM_DRIVER_NAME nouveau
 74#include "interface/drm.h"
 75IMPL(nouveau_context, wld_context)
 76IMPL(nouveau_renderer, wld_renderer)
 77IMPL(nouveau_buffer, wld_buffer)
 78
 79static void
 80pack_gray_row_to_mono(uint8_t *dst, const uint8_t *src, uint32_t width)
 81{
 82	uint32_t x, bytes_per_row;
 83
 84	bytes_per_row = (width + 7) / 8;
 85	memset(dst, 0, bytes_per_row);
 86
 87	for (x = 0; x < width; ++x) {
 88		if (src[x] >= 128)
 89			dst[x / 8] |= 0x80 >> (x & 7);
 90	}
 91}
 92
 93/**** DRM driver ****/
 94bool
 95driver_device_supported(uint32_t vendor_id, uint32_t device_id)
 96{
 97	return vendor_id == 0x10de;
 98}
 99
100struct wld_context *
101driver_create_context(int drm_fd)
102{
103	struct nouveau_context *context;
104
105	if (!(context = malloc(sizeof *context)))
106		goto error0;
107
108	if (nouveau_device_wrap(drm_fd, 0, &context->device) != 0)
109		goto error1;
110
111	switch (context->device->chipset & ~0xf) {
112	/* TODO: Support NV50
113	case 0x50:
114	case 0x80:
115	case 0x90:
116	case 0xa0:
117		context->architecture = NV_ARCH_50;
118		break;
119	*/
120	case 0xc0:
121	case 0xd0:
122		context->architecture = NV_ARCH_C0;
123		break;
124	/* TODO: Support NVE0
125	case 0xe0:
126	case 0xf0:
127	case 0x100:
128		context->architecture = NV_ARCH_E0;
129		break;
130	*/
131	default:
132		return NULL;
133	}
134
135	if (nouveau_client_new(context->device, &context->client) != 0)
136		goto error2;
137
138	context_initialize(&context->base, &wld_context_impl);
139
140	return &context->base;
141
142error2:
143	nouveau_device_del(&context->device);
144error1:
145	free(context);
146error0:
147	return NULL;
148}
149
150/**** Context ****/
151static inline bool
152ensure_space(struct nouveau_pushbuf *push, uint32_t count)
153{
154	if (push->end - push->cur > count)
155		return true;
156
157	return nouveau_pushbuf_space(push, count, 0, 0) == 0;
158}
159
160static inline void
161nv_add_dword(struct nouveau_pushbuf *push, uint32_t dword)
162{
163	*push->cur++ = dword;
164}
165
166static inline void
167nv_add_dwords_va(struct nouveau_pushbuf *push, uint16_t count, va_list dwords)
168{
169	while (count--)
170		nv_add_dword(push, va_arg(dwords, uint32_t));
171}
172
173static inline void
174nv_add_data(struct nouveau_pushbuf *push, void *data, uint32_t count)
175{
176	memcpy(push->cur, data, count * 4);
177	push->cur += count;
178}
179
180static inline uint32_t
181nvc0_format(uint32_t format)
182{
183	switch (format) {
184	case WLD_FORMAT_XRGB8888:
185		return G80_SURFACE_FORMAT_BGRX8_UNORM;
186	case WLD_FORMAT_ARGB8888:
187		return G80_SURFACE_FORMAT_BGRA8_UNORM;
188	}
189
190	return 0;
191}
192
193enum {
194	GF100_COMMAND_TYPE_INCREASING = 1,
195	GF100_COMMAND_TYPE_NON_INCREASING = 3,
196	GF100_COMMAND_TYPE_INLINE = 4
197};
198
199enum {
200	GF100_SUBCHANNEL_2D = 3,
201};
202
203static inline uint32_t
204nvc0_command(uint8_t type, uint8_t subchannel, uint16_t method, uint16_t count_or_value)
205{
206	return type << 29 | count_or_value << 16 | subchannel << 13 | method >> 2;
207}
208
209static inline void
210nvc0_inline(struct nouveau_pushbuf *push, uint8_t subchannel, uint16_t method, uint16_t value)
211{
212	nv_add_dword(push, nvc0_command(GF100_COMMAND_TYPE_INLINE,
213	                                subchannel, method, value));
214}
215
216static inline void
217nvc0_methods(struct nouveau_pushbuf *push,
218             uint8_t subchannel, uint16_t start_method,
219             uint16_t count, ...)
220{
221	va_list dwords;
222	nv_add_dword(push, nvc0_command(GF100_COMMAND_TYPE_INCREASING,
223	                                subchannel, start_method, count));
224	va_start(dwords, count);
225	nv_add_dwords_va(push, count, dwords);
226	va_end(dwords);
227}
228
229#define nvc0_2d(push, method, count, ...) \
230	nvc0_methods(push, GF100_SUBCHANNEL_2D, method, count, __VA_ARGS__)
231#define nvc0_2d_inline(push, method, value) \
232	nvc0_inline(push, GF100_SUBCHANNEL_2D, method, value)
233
234static bool
235nvc0_2d_initialize(struct nouveau_renderer *renderer)
236{
237	int ret;
238
239	ret = nouveau_object_new(renderer->channel, GF100_2D, GF100_2D, NULL, 0,
240	                         &renderer->nvc0_2d);
241
242	if (ret != 0)
243		goto error0;
244
245	if (!ensure_space(renderer->pushbuf, 5))
246		goto error1;
247
248	nvc0_2d(renderer->pushbuf, NV1_SUBCHAN_OBJECT, 1,
249	        renderer->nvc0_2d->handle);
250	nvc0_2d_inline(renderer->pushbuf, G80_2D_OPERATION,
251	               G80_2D_OPERATION_SRCCOPY_AND);
252	nvc0_2d_inline(renderer->pushbuf, G80_2D_UNK0884, 0x3f);
253	nvc0_2d_inline(renderer->pushbuf, G80_2D_UNK0888, 1);
254
255	return true;
256
257error1:
258	nouveau_object_del(&renderer->nvc0_2d);
259error0:
260	return false;
261}
262
263static void
264nvc0_2d_finalize(struct nouveau_renderer *renderer)
265{
266	nouveau_object_del(&renderer->nvc0_2d);
267}
268
269struct wld_renderer *
270context_create_renderer(struct wld_context *base)
271{
272	struct nouveau_context *context = nouveau_context(base);
273	struct nouveau_renderer *renderer;
274	struct nvc0_fifo fifo = {};
275	int ret;
276
277	if (!(renderer = malloc(sizeof *renderer)))
278		goto error0;
279
280	ret = nouveau_object_new(&context->device->object, 0,
281	                         NOUVEAU_FIFO_CHANNEL_CLASS, &fifo, sizeof fifo,
282	                         &renderer->channel);
283
284	if (ret != 0)
285		goto error1;
286
287	ret = nouveau_pushbuf_new(context->client, renderer->channel, 4, 32 * 1024,
288	                          true, &renderer->pushbuf);
289
290	if (ret != 0)
291		goto error2;
292
293	if (nouveau_bufctx_new(context->client, 1, &renderer->bufctx) != 0)
294		goto error3;
295
296	if (!nvc0_2d_initialize(renderer))
297		goto error4;
298
299	renderer_initialize(&renderer->base, &wld_renderer_impl);
300	renderer->target = NULL;
301
302	return &renderer->base;
303
304error4:
305	nouveau_bufctx_del(&renderer->bufctx);
306error3:
307	nouveau_pushbuf_del(&renderer->pushbuf);
308error2:
309	nouveau_object_del(&renderer->channel);
310error1:
311	free(renderer);
312error0:
313	return NULL;
314}
315
316static bool export(struct wld_exporter *exporter, struct wld_buffer *base,
317                   uint32_t type, union wld_object *object)
318{
319	struct nouveau_buffer *buffer = nouveau_buffer(base);
320
321	switch (type) {
322	case WLD_DRM_OBJECT_HANDLE:
323		object->u32 = buffer->bo->handle;
324		return true;
325	case WLD_DRM_OBJECT_PRIME_FD:
326		if (nouveau_bo_set_prime(buffer->bo, &object->i) != 0)
327			return false;
328		return true;
329	default:
330		return false;
331	}
332}
333
334static struct nouveau_buffer *
335new_buffer(struct nouveau_context *context,
336           uint32_t width, uint32_t height,
337           uint32_t format, uint32_t pitch)
338{
339	struct nouveau_buffer *buffer;
340
341	if (!(buffer = malloc(sizeof *buffer)))
342		return NULL;
343
344	buffer_initialize(&buffer->base, &wld_buffer_impl,
345	                  width, height, format, pitch);
346	buffer->context = context;
347	buffer->exporter.export = &export;
348	wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
349
350	return buffer;
351}
352
353static inline uint32_t
354roundup(uint32_t value, uint32_t alignment)
355{
356	return (value + alignment - 1) & ~(alignment - 1);
357}
358
359struct buffer *
360context_create_buffer(struct wld_context *base,
361                      uint32_t width, uint32_t height,
362                      uint32_t format, uint32_t flags)
363{
364	struct nouveau_context *context = nouveau_context(base);
365	struct nouveau_buffer *buffer;
366	uint32_t bpp = format_bytes_per_pixel(format),
367	         pitch = roundup(width * bpp, 64), bo_flags;
368	union nouveau_bo_config config = {};
369
370	if (!(buffer = new_buffer(context, width, height, format, pitch)))
371		goto error0;
372
373	bo_flags = NOUVEAU_BO_VRAM;
374
375	if (flags & WLD_DRM_FLAG_SCANOUT)
376		bo_flags |= NOUVEAU_BO_CONTIG;
377
378	if (height > 0x40 && !(flags & WLD_FLAG_MAP)) {
379		config.nvc0.tile_mode = 0x40;
380		config.nvc0.memtype = 0xfe;
381		height = roundup(height, 0x80);
382	} else
383		bo_flags |= NOUVEAU_BO_MAP;
384
385	if (nouveau_bo_new(context->device, bo_flags, 0, pitch * height,
386	                   &config, &buffer->bo)
387	    != 0) {
388		goto error1;
389	}
390
391	return &buffer->base;
392
393error1:
394	free(buffer);
395error0:
396	return NULL;
397}
398
399struct buffer *
400context_import_buffer(struct wld_context *base,
401                      uint32_t type, union wld_object object,
402                      uint32_t width, uint32_t height,
403                      uint32_t format, uint32_t pitch)
404{
405	struct nouveau_context *context = (void *)base;
406	struct nouveau_buffer *buffer;
407	struct nouveau_bo *bo = NULL;
408
409	switch (type) {
410	case WLD_DRM_OBJECT_PRIME_FD:
411		if (nouveau_bo_prime_handle_ref(context->device,
412		                                object.i, &bo)
413		    != 0) {
414			goto error0;
415		}
416		break;
417	default:
418		goto error0;
419	}
420
421	if (!(buffer = new_buffer(context, width, height, format, pitch)))
422		goto error1;
423
424	buffer->bo = bo;
425
426	return &buffer->base;
427
428error1:
429	nouveau_bo_ref(NULL, &buffer->bo);
430error0:
431	return NULL;
432}
433
434void
435context_destroy(struct wld_context *base)
436{
437	struct nouveau_context *context = nouveau_context(base);
438
439	nouveau_client_del(&context->client);
440	nouveau_device_del(&context->device);
441	free(context);
442}
443
444/**** Renderer ****/
445uint32_t
446renderer_capabilities(struct wld_renderer *renderer,
447                      struct buffer *buffer)
448{
449	if (buffer->base.impl == &wld_buffer_impl)
450		return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
451
452	return 0;
453}
454
455bool
456renderer_set_target(struct wld_renderer *base, struct buffer *buffer)
457{
458	struct nouveau_renderer *renderer = nouveau_renderer(base);
459
460	if (buffer && buffer->base.impl != &wld_buffer_impl)
461		return false;
462
463	renderer->target = buffer ? nouveau_buffer(&buffer->base) : NULL;
464
465	return true;
466}
467
468static inline void
469nvc0_2d_use_buffer(struct nouveau_renderer *renderer,
470                   struct nouveau_buffer *buffer,
471                   uint16_t format_method, uint16_t format)
472{
473	uint32_t access = format == G80_2D_SRC_FORMAT ? NOUVEAU_BO_RD
474	                                              : NOUVEAU_BO_WR;
475
476	nvc0_2d_inline(renderer->pushbuf, format_method, format);
477
478	if (buffer->bo->config.nvc0.memtype) {
479		nvc0_2d(renderer->pushbuf, format_method + 0x04, 2,
480		        0, buffer->bo->config.nvc0.tile_mode);
481	} else {
482		nvc0_2d_inline(renderer->pushbuf, format_method + 0x04, 1);
483		nvc0_2d(renderer->pushbuf, format_method + 0x14, 1,
484		        buffer->base.base.pitch);
485	}
486
487	nvc0_2d(renderer->pushbuf, format_method + 0x18, 4,
488	        buffer->base.base.width, buffer->base.base.height,
489	        buffer->bo->offset >> 32, buffer->bo->offset);
490	nouveau_bufctx_refn(renderer->bufctx, 0, buffer->bo,
491	                    NOUVEAU_BO_VRAM | access);
492}
493
494void
495renderer_fill_rectangle(struct wld_renderer *base, uint32_t color,
496                        int32_t x, int32_t y,
497                        uint32_t width, uint32_t height)
498{
499	struct nouveau_renderer *renderer = nouveau_renderer(base);
500	struct nouveau_buffer *dst = renderer->target;
501	uint32_t format;
502
503	if (!ensure_space(renderer->pushbuf, 18))
504		return;
505
506	format = nvc0_format(dst->base.base.format);
507
508	nouveau_bufctx_reset(renderer->bufctx, 0);
509	nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, format);
510	nvc0_2d(renderer->pushbuf, G80_2D_DRAW_SHAPE, 3,
511	        G80_2D_DRAW_SHAPE_RECTANGLES, format, color);
512	nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
513
514	if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
515		return;
516
517	nvc0_2d(renderer->pushbuf, G80_2D_DRAW_POINT32_X(0), 4,
518	        x, y, x + width, y + height);
519}
520
521void
522renderer_copy_rectangle(struct wld_renderer *base,
523                        struct buffer *buffer_base,
524                        int32_t dst_x, int32_t dst_y,
525                        int32_t src_x, int32_t src_y,
526                        uint32_t width, uint32_t height)
527{
528	struct nouveau_renderer *renderer = nouveau_renderer(base);
529
530	if (buffer_base->base.impl != &wld_buffer_impl)
531		return;
532
533	struct nouveau_buffer *src = nouveau_buffer(&buffer_base->base),
534	                      *dst = renderer->target;
535	uint32_t src_format, dst_format;
536
537	if (!ensure_space(renderer->pushbuf, 33))
538		return;
539
540	src_format = nvc0_format(src->base.base.format);
541	dst_format = nvc0_format(dst->base.base.format);
542
543	nouveau_bufctx_reset(renderer->bufctx, 0);
544	nvc0_2d_use_buffer(renderer, src, G80_2D_SRC_FORMAT, src_format);
545	nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, dst_format);
546	nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
547
548	if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
549		return;
550
551	nvc0_2d_inline(renderer->pushbuf, G80_GRAPH_SERIALIZE, 0);
552	nvc0_2d_inline(renderer->pushbuf, G80_2D_BLIT_CONTROL,
553	               G80_2D_BLIT_CONTROL_ORIGIN_CENTER
554	                   | G80_2D_BLIT_CONTROL_FILTER_POINT_SAMPLE);
555	nvc0_2d(renderer->pushbuf, G80_2D_BLIT_DST_X, 12,
556	        dst_x, dst_y, width, height, 0, 1, 0, 1, 0, src_x, 0, src_y);
557
558	renderer_flush(base);
559}
560
561void
562renderer_draw_text(struct wld_renderer *base,
563                   struct font *font, uint32_t color,
564                   int32_t x, int32_t y, const char *text,
565                   uint32_t length, struct wld_extents *extents)
566{
567	struct nouveau_renderer *renderer = nouveau_renderer(base);
568	struct nouveau_buffer *dst = renderer->target;
569	uint32_t format;
570	int ret;
571	struct glyph *glyph;
572	FT_UInt glyph_index;
573	uint32_t c, count;
574	int32_t origin_x = x;
575
576	if (!ensure_space(renderer->pushbuf, 17))
577		return;
578
579	format = nvc0_format(dst->base.base.format);
580
581	nouveau_bufctx_reset(renderer->bufctx, 0);
582	nvc0_2d_use_buffer(renderer, dst, G80_2D_DST_FORMAT, format);
583	nvc0_2d_inline(renderer->pushbuf, G80_2D_SIFC_BITMAP_ENABLE, 1);
584	nvc0_2d(renderer->pushbuf, G80_2D_SIFC_BITMAP_FORMAT, 6,
585	        G80_2D_SIFC_BITMAP_FORMAT_I1,
586	        0, /* SIFC_FORMAT */
587	        G80_2D_SIFC_BITMAP_LINE_PACK_MODE_ALIGN_BYTE,
588	        0, color, /* SIFC_BITMAP_COLOR_BIT0, SIFC_BITMAP_COLOR_BIT1 */
589	        0         /* SIFC_BITMAP_WRITE_BIT0_ENABLE */
590	);
591	nouveau_pushbuf_bufctx(renderer->pushbuf, renderer->bufctx);
592
593	if (nouveau_pushbuf_validate(renderer->pushbuf) != 0)
594		return;
595
596	if (length == -1)
597		length = strlen(text);
598
599	while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') {
600		text += ret;
601		length -= ret;
602		glyph_index = FT_Get_Char_Index(font->face, c);
603
604		if (!font_ensure_glyph(font, glyph_index))
605			continue;
606
607		glyph = font->glyphs[glyph_index];
608
609		if (glyph->bitmap.width == 0 || glyph->bitmap.rows == 0)
610			goto advance;
611
612		if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
613			count = (glyph->bitmap.pitch * glyph->bitmap.rows + 3) / 4;
614		} else {
615			uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
616			count = (bytes_per_row * glyph->bitmap.rows + 3) / 4;
617		}
618
619		if (!ensure_space(renderer->pushbuf, 12 + count))
620			return;
621
622		if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
623			nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
624			        /* Use the pitch instead of width to ensure the correct
625				 * alignment is used. */
626			        glyph->bitmap.pitch * 8, glyph->bitmap.rows,
627			        0, 1, 0, 1,
628			        0, origin_x + glyph->x, 0, y + glyph->y);
629			nv_add_dword(renderer->pushbuf,
630			             nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
631			                          GF100_SUBCHANNEL_2D,
632			                          G80_2D_SIFC_DATA, count));
633			nv_add_data(renderer->pushbuf, glyph->bitmap.buffer, count);
634		} else {
635			uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
636			uint32_t row;
637			uint8_t *mono = malloc(bytes_per_row * glyph->bitmap.rows);
638			uint8_t *dst = mono;
639
640			if (!mono)
641				return;
642
643			for (row = 0; row < glyph->bitmap.rows; ++row) {
644				const uint8_t *src = glyph->bitmap.buffer +
645				                     (row * glyph->bitmap.pitch);
646				pack_gray_row_to_mono(dst, src, glyph->bitmap.width);
647				dst += bytes_per_row;
648			}
649
650			nvc0_2d(renderer->pushbuf, G80_2D_SIFC_WIDTH, 10,
651			        bytes_per_row * 8, glyph->bitmap.rows,
652			        0, 1, 0, 1,
653			        0, origin_x + glyph->x, 0, y + glyph->y);
654			nv_add_dword(renderer->pushbuf,
655			             nvc0_command(GF100_COMMAND_TYPE_NON_INCREASING,
656			                          GF100_SUBCHANNEL_2D,
657			                          G80_2D_SIFC_DATA, count));
658			nv_add_data(renderer->pushbuf, mono, count);
659			free(mono);
660		}
661
662	advance:
663		origin_x += glyph->advance;
664	}
665
666	if (extents)
667		extents->advance = origin_x - x;
668}
669
670void
671renderer_flush(struct wld_renderer *base)
672{
673	struct nouveau_renderer *renderer = nouveau_renderer(base);
674
675	nouveau_pushbuf_kick(renderer->pushbuf, renderer->channel);
676	nouveau_pushbuf_bufctx(renderer->pushbuf, NULL);
677}
678
679void
680renderer_destroy(struct wld_renderer *base)
681{
682	struct nouveau_renderer *renderer = nouveau_renderer(base);
683
684	nvc0_2d_finalize(renderer);
685	nouveau_bufctx_del(&renderer->bufctx);
686	nouveau_pushbuf_del(&renderer->pushbuf);
687	nouveau_object_del(&renderer->channel);
688	free(renderer);
689}
690
691/**** Buffer ****/
692bool
693buffer_map(struct buffer *base)
694{
695	struct nouveau_buffer *buffer = nouveau_buffer(&base->base);
696
697	/* If the buffer is tiled, it cannot be mapped into virtual memory in order
698	 * to appear linear like intel can do with map_gtt. */
699	if (buffer->bo->config.nvc0.tile_mode)
700		return false;
701
702	if (nouveau_bo_map(buffer->bo, NOUVEAU_BO_WR,
703	                   buffer->context->client)
704	    != 0) {
705		return false;
706	}
707
708	buffer->base.base.map = buffer->bo->map;
709
710	return true;
711}
712
713bool
714buffer_unmap(struct buffer *base)
715{
716	struct nouveau_buffer *buffer = nouveau_buffer(&base->base);
717
718	if (munmap(buffer->bo->map, buffer->bo->size) == -1)
719		return false;
720
721	buffer->bo->map = NULL;
722	base->base.map = NULL;
723
724	return true;
725}
726
727void
728buffer_destroy(struct buffer *base)
729{
730	struct nouveau_buffer *buffer = nouveau_buffer(&base->base);
731
732	nouveau_bo_ref(NULL, &buffer->bo);
733	free(buffer);
734}