1 /*
2  * Copyright 2012  Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <sys/mman.h>
27 #include <gbm.h>
28 #include "amdgpu_drv.h"
29 #include "amdgpu_bo_helper.h"
30 #include "amdgpu_glamor.h"
31 #include "amdgpu_pixmap.h"
32 
33 static uint32_t
amdgpu_get_gbm_format(int depth,int bitsPerPixel)34 amdgpu_get_gbm_format(int depth, int bitsPerPixel)
35 {
36 	switch (depth) {
37 #ifdef GBM_FORMAT_R8
38 	case 8:
39 		return GBM_FORMAT_R8;
40 #endif
41 	case 15:
42 		return GBM_FORMAT_ARGB1555;
43 	case 16:
44 		return GBM_FORMAT_RGB565;
45 	case 32:
46 		return GBM_FORMAT_ARGB8888;
47 	case 30:
48 		return GBM_FORMAT_XRGB2101010;
49 	case 24:
50 		if (bitsPerPixel == 32)
51 			return GBM_FORMAT_XRGB8888;
52 		/* fall through */
53 	default:
54 		ErrorF("%s: Unsupported depth/bpp %d/%d\n", __func__,
55 		       depth, bitsPerPixel);
56 		return ~0U;
57 	}
58 }
59 
60 /* Calculate appropriate pitch for a pixmap and allocate a BO that can hold it.
61  */
amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn,int width,int height,int depth,int usage_hint,int bitsPerPixel,int * new_pitch)62 struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width,
63 					      int height, int depth, int usage_hint,
64 					      int bitsPerPixel, int *new_pitch)
65 {
66 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
67 	struct amdgpu_buffer *pixmap_buffer;
68 
69 	if (!(usage_hint & AMDGPU_CREATE_PIXMAP_GTT) && info->gbm) {
70 		uint32_t bo_use = GBM_BO_USE_RENDERING;
71 		uint32_t gbm_format = amdgpu_get_gbm_format(depth, bitsPerPixel);
72 
73 		if (gbm_format == ~0U)
74 			return NULL;
75 
76 		pixmap_buffer = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer));
77 		if (!pixmap_buffer) {
78 			return NULL;
79 		}
80 		pixmap_buffer->ref_count = 1;
81 
82 		if ( bitsPerPixel == pScrn->bitsPerPixel)
83 			bo_use |= GBM_BO_USE_SCANOUT;
84 
85 #ifdef HAVE_GBM_BO_USE_LINEAR
86 		if (usage_hint == CREATE_PIXMAP_USAGE_SHARED ||
87 		    (usage_hint & AMDGPU_CREATE_PIXMAP_LINEAR)) {
88 			bo_use |= GBM_BO_USE_LINEAR;
89 		}
90 #endif
91 
92 		pixmap_buffer->bo.gbm = gbm_bo_create(info->gbm, width, height,
93 						      gbm_format,
94 						      bo_use);
95 		if (!pixmap_buffer->bo.gbm) {
96 			free(pixmap_buffer);
97 			return NULL;
98 		}
99 
100 		pixmap_buffer->flags |= AMDGPU_BO_FLAGS_GBM;
101 
102 		if (new_pitch)
103 			*new_pitch = gbm_bo_get_stride(pixmap_buffer->bo.gbm);
104 	} else {
105 		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
106 		unsigned cpp = (bitsPerPixel + 7) / 8;
107 		unsigned pitch = cpp *
108 			AMDGPU_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp));
109 		uint32_t domain = (usage_hint & AMDGPU_CREATE_PIXMAP_GTT) ?
110 			AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM;
111 
112 		pixmap_buffer = amdgpu_bo_open(pAMDGPUEnt->pDev, pitch * height,
113 					       4096, domain);
114 
115 		if (new_pitch)
116 			*new_pitch = pitch;
117 	}
118 
119 	return pixmap_buffer;
120 }
121 
122 /* Clear the pixmap contents to black */
123 void
amdgpu_pixmap_clear(PixmapPtr pixmap)124 amdgpu_pixmap_clear(PixmapPtr pixmap)
125 {
126 	ScreenPtr screen = pixmap->drawable.pScreen;
127 	AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen));
128 	GCPtr gc = GetScratchGC(pixmap->drawable.depth, screen);
129 	xRectangle rect;
130 
131 	ValidateGC(&pixmap->drawable, gc);
132 	rect.x = 0;
133 	rect.y = 0;
134 	rect.width = pixmap->drawable.width;
135 	rect.height = pixmap->drawable.height;
136 	info->force_accel = TRUE;
137 	gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect);
138 	info->force_accel = FALSE;
139 	FreeScratchGC(gc);
140 }
141 
amdgpu_bo_get_handle(struct amdgpu_buffer * bo,uint32_t * handle)142 Bool amdgpu_bo_get_handle(struct amdgpu_buffer *bo, uint32_t *handle)
143 {
144 	if (bo->flags & AMDGPU_BO_FLAGS_GBM) {
145 		*handle = gbm_bo_get_handle(bo->bo.gbm).u32;
146 		return TRUE;
147 	}
148 
149 	return amdgpu_bo_export(bo->bo.amdgpu, amdgpu_bo_handle_type_kms,
150 				handle) == 0;
151 }
152 
153 #ifdef USE_GLAMOR
154 
amdgpu_pixmap_do_get_tiling_info(PixmapPtr pixmap)155 static void amdgpu_pixmap_do_get_tiling_info(PixmapPtr pixmap)
156 {
157 	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
158 	ScreenPtr screen = pixmap->drawable.pScreen;
159 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
160 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
161 	struct drm_amdgpu_gem_metadata gem_metadata;
162 
163 	gem_metadata.handle = priv->handle;
164 	gem_metadata.op = AMDGPU_GEM_METADATA_OP_GET_METADATA;
165 
166 	if (drmCommandWriteRead(pAMDGPUEnt->fd, DRM_AMDGPU_GEM_METADATA,
167 				&gem_metadata, sizeof(gem_metadata)) == 0)
168 		priv->tiling_info = gem_metadata.data.tiling_info;
169 }
170 
171 #endif
172 
amdgpu_pixmap_get_tiling_info(PixmapPtr pixmap)173 uint64_t amdgpu_pixmap_get_tiling_info(PixmapPtr pixmap)
174 {
175 	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
176 	uint32_t handle;
177 
178 	if (!priv || !priv->handle_valid) {
179 		amdgpu_pixmap_get_handle(pixmap, &handle);
180 		priv = amdgpu_get_pixmap_private(pixmap);
181 	}
182 
183 	return priv->tiling_info;
184 }
185 
amdgpu_pixmap_get_handle(PixmapPtr pixmap,uint32_t * handle)186 Bool amdgpu_pixmap_get_handle(PixmapPtr pixmap, uint32_t *handle)
187 {
188 #ifdef USE_GLAMOR
189 	ScreenPtr screen = pixmap->drawable.pScreen;
190 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
191 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
192 #endif
193 	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
194 
195 	if (!priv) {
196 		priv = calloc(1, sizeof(*priv));
197 		amdgpu_set_pixmap_private(pixmap, priv);
198 	}
199 
200 	if (priv->handle_valid)
201 		goto success;
202 
203 #ifdef USE_GLAMOR
204 	if (info->use_glamor) {
205 		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
206 		CARD16 stride;
207 		CARD32 size;
208 		int fd, r;
209 
210 		fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size);
211 		if (fd < 0)
212 			return FALSE;
213 
214 		r = drmPrimeFDToHandle(pAMDGPUEnt->fd, fd, &priv->handle);
215 		close(fd);
216 		if (r)
217 			return FALSE;
218 
219 		amdgpu_pixmap_do_get_tiling_info(pixmap);
220 		goto success;
221 	}
222 #endif
223 
224 	if (!priv->bo || !amdgpu_bo_get_handle(priv->bo, &priv->handle))
225 		return FALSE;
226 
227  success:
228 	priv->handle_valid = TRUE;
229 	*handle = priv->handle;
230 	return TRUE;
231 }
232 
amdgpu_bo_map(ScrnInfoPtr pScrn,struct amdgpu_buffer * bo)233 int amdgpu_bo_map(ScrnInfoPtr pScrn, struct amdgpu_buffer *bo)
234 {
235 	int ret = 0;
236 
237 	if (bo->flags & AMDGPU_BO_FLAGS_GBM) {
238 		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
239 		uint32_t handle, stride, height;
240 		union drm_amdgpu_gem_mmap args;
241 		int fd = pAMDGPUEnt->fd;
242 		void *ptr;
243 
244 		handle = gbm_bo_get_handle(bo->bo.gbm).u32;
245 		stride = gbm_bo_get_stride(bo->bo.gbm);
246 		height = gbm_bo_get_height(bo->bo.gbm);
247 
248 		memset(&args, 0, sizeof(union drm_amdgpu_gem_mmap));
249 		args.in.handle = handle;
250 
251 		ret = drmCommandWriteRead(fd, DRM_AMDGPU_GEM_MMAP,
252 					&args, sizeof(args));
253 		if (ret) {
254 			ErrorF("Failed to get the mmap offset\n");
255 			return ret;
256 		}
257 
258 		ptr = mmap(NULL, stride * height,
259 			PROT_READ | PROT_WRITE, MAP_SHARED,
260 			fd, args.out.addr_ptr);
261 
262 		if (!ptr) {
263 			ErrorF("Failed to mmap the bo\n");
264 			return -1;
265 		}
266 
267 		bo->cpu_ptr = ptr;
268 	} else
269 		ret = amdgpu_bo_cpu_map(bo->bo.amdgpu, &bo->cpu_ptr);
270 
271 	return ret;
272 }
273 
amdgpu_bo_unmap(struct amdgpu_buffer * bo)274 void amdgpu_bo_unmap(struct amdgpu_buffer *bo)
275 {
276 	if (!bo->cpu_ptr)
277 		return;
278 
279 	if (bo->flags & AMDGPU_BO_FLAGS_GBM) {
280 		uint32_t stride, height;
281 		stride = gbm_bo_get_stride(bo->bo.gbm);
282 		height = gbm_bo_get_height(bo->bo.gbm);
283 		munmap(bo->cpu_ptr, stride * height);
284 	} else
285 		amdgpu_bo_cpu_unmap(bo->bo.amdgpu);
286 }
287 
amdgpu_bo_open(amdgpu_device_handle pDev,uint32_t alloc_size,uint32_t phys_alignment,uint32_t domains)288 struct amdgpu_buffer *amdgpu_bo_open(amdgpu_device_handle pDev,
289 				       uint32_t alloc_size,
290 				       uint32_t phys_alignment,
291 				       uint32_t domains)
292 {
293 	struct amdgpu_bo_alloc_request alloc_request;
294 	struct amdgpu_buffer *bo = NULL;
295 
296 	memset(&alloc_request, 0, sizeof(struct amdgpu_bo_alloc_request));
297 
298 	bo = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer));
299 	if (!bo)
300 		return NULL;
301 
302 	alloc_request.alloc_size = alloc_size;
303 	alloc_request.phys_alignment = phys_alignment;
304 	alloc_request.preferred_heap = domains;
305 
306 	if (amdgpu_bo_alloc(pDev, &alloc_request, &bo->bo.amdgpu)) {
307 		free(bo);
308 		return NULL;
309 	}
310 
311 	bo->ref_count = 1;
312 
313 	return bo;
314 }
315 
amdgpu_bo_ref(struct amdgpu_buffer * buffer)316 void amdgpu_bo_ref(struct amdgpu_buffer *buffer)
317 {
318 	buffer->ref_count++;
319 }
320 
amdgpu_bo_unref(struct amdgpu_buffer ** buffer)321 void amdgpu_bo_unref(struct amdgpu_buffer **buffer)
322 {
323 	struct amdgpu_buffer *buf = *buffer;
324 
325 	buf->ref_count--;
326 	if (buf->ref_count) {
327 		return;
328 	}
329 
330 	amdgpu_bo_unmap(buf);
331 
332 	if (buf->flags & AMDGPU_BO_FLAGS_GBM) {
333 		gbm_bo_destroy(buf->bo.gbm);
334 	} else {
335 		amdgpu_bo_free(buf->bo.amdgpu);
336 	}
337 	free(buf);
338 	*buffer = NULL;
339 }
340 
amdgpu_query_bo_size(amdgpu_bo_handle buf_handle,uint32_t * size)341 int amdgpu_query_bo_size(amdgpu_bo_handle buf_handle, uint32_t *size)
342 {
343 	struct amdgpu_bo_info buffer_info;
344 	int ret;
345 
346 	memset(&buffer_info, 0, sizeof(struct amdgpu_bo_info));
347 	ret = amdgpu_bo_query_info(buf_handle, &buffer_info);
348 	if (ret)
349 		*size = 0;
350 	else
351 		*size = (uint32_t)(buffer_info.alloc_size);
352 
353 	return ret;
354 }
355 
amdgpu_query_heap_size(amdgpu_device_handle pDev,uint32_t heap,uint64_t * heap_size,uint64_t * max_allocation)356 int amdgpu_query_heap_size(amdgpu_device_handle pDev,
357 			    uint32_t heap,
358 			    uint64_t *heap_size,
359 			    uint64_t *max_allocation)
360 {
361 	struct amdgpu_heap_info heap_info;
362 	int ret;
363 
364 	memset(&heap_info, 0, sizeof(struct amdgpu_heap_info));
365 	ret = amdgpu_query_heap_info(pDev, heap, 0, &heap_info);
366 	if (ret) {
367 		*heap_size = 0;
368 		*max_allocation = 0;
369 	} else {
370 		*heap_size = heap_info.heap_size;
371 		*max_allocation = heap_info.max_allocation;
372 	}
373 
374 	return ret;
375 }
376 
amdgpu_gem_bo_open_prime(amdgpu_device_handle pDev,int fd_handle,uint32_t size)377 struct amdgpu_buffer *amdgpu_gem_bo_open_prime(amdgpu_device_handle pDev,
378 						 int fd_handle,
379 						 uint32_t size)
380 {
381 	struct amdgpu_buffer *bo = NULL;
382 	struct amdgpu_bo_import_result buffer = {0};
383 
384 	bo = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer));
385 	if (!bo)
386 		return NULL;
387 
388 	if (amdgpu_bo_import(pDev, amdgpu_bo_handle_type_dma_buf_fd,
389 			     (uint32_t)fd_handle, &buffer)) {
390 		free(bo);
391 		return FALSE;
392 	}
393 	bo->bo.amdgpu = buffer.buf_handle;
394 	bo->ref_count = 1;
395 
396 	return bo;
397 }
398 
399 
amdgpu_set_shared_pixmap_backing(PixmapPtr ppix,void * fd_handle)400 Bool amdgpu_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle)
401 {
402 	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
403 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
404 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
405 	struct amdgpu_buffer *pixmap_buffer = NULL;
406 	int ihandle = (int)(long)fd_handle;
407 	uint32_t size = ppix->devKind * ppix->drawable.height;
408 	Bool ret;
409 
410 	if (ihandle == -1)
411 		return amdgpu_set_pixmap_bo(ppix, NULL);
412 
413 	if (info->gbm) {
414 		struct amdgpu_buffer *bo;
415 		struct gbm_import_fd_data data;
416 		uint32_t bo_use = GBM_BO_USE_RENDERING;
417 
418 		data.format = amdgpu_get_gbm_format(ppix->drawable.depth,
419 						    ppix->drawable.bitsPerPixel);
420 		if (data.format == ~0U)
421 			return FALSE;
422 
423 		bo = calloc(1, sizeof(struct amdgpu_buffer));
424 		if (!bo)
425 			return FALSE;
426 		bo->ref_count = 1;
427 
428 		data.fd = ihandle;
429 		data.width = ppix->drawable.width;
430 		data.height = ppix->drawable.height;
431 		data.stride = ppix->devKind;
432 
433 		if (ppix->drawable.bitsPerPixel == pScrn->bitsPerPixel)
434 			bo_use |= GBM_BO_USE_SCANOUT;
435 
436 		bo->bo.gbm = gbm_bo_import(info->gbm, GBM_BO_IMPORT_FD, &data,
437 					   bo_use);
438 		if (!bo->bo.gbm) {
439 			free(bo);
440 			return FALSE;
441 		}
442 
443 		bo->flags |= AMDGPU_BO_FLAGS_GBM;
444 
445 #ifdef USE_GLAMOR
446 		if (info->use_glamor &&
447 		    !amdgpu_glamor_create_textured_pixmap(ppix, bo)) {
448 			amdgpu_bo_unref(&bo);
449 			return FALSE;
450 		}
451 #endif
452 
453 		ret = amdgpu_set_pixmap_bo(ppix, bo);
454 		/* amdgpu_set_pixmap_bo increments ref_count if it succeeds */
455 		amdgpu_bo_unref(&bo);
456 		return ret;
457 	}
458 
459 	pixmap_buffer = amdgpu_gem_bo_open_prime(pAMDGPUEnt->pDev, ihandle, size);
460 	if (!pixmap_buffer) {
461 		return FALSE;
462 	}
463 
464 	close(ihandle);
465 
466 	ret = amdgpu_set_pixmap_bo(ppix, pixmap_buffer);
467 
468 	/* we have a reference from the alloc and one from set pixmap bo,
469 	   drop one */
470 	amdgpu_bo_unref(&pixmap_buffer);
471 
472 	return ret;
473 }
474