1/*
2 * Copyright © 2014 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including
13 * the next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef AMDGPU_PIXMAP_H
27#define AMDGPU_PIXMAP_H
28
29#include "amdgpu_drv.h"
30
31struct amdgpu_pixmap {
32	uint_fast32_t gpu_read;
33	uint_fast32_t gpu_write;
34
35	uint64_t tiling_info;
36
37	struct amdgpu_buffer *bo;
38	struct drmmode_fb *fb;
39	Bool fb_failed;
40
41	/* GEM handle for pixmaps shared via DRI2/3 */
42	Bool handle_valid;
43	uint32_t handle;
44};
45
46extern DevPrivateKeyRec amdgpu_pixmap_index;
47
48static inline struct amdgpu_pixmap *amdgpu_get_pixmap_private(PixmapPtr pixmap)
49{
50	return dixGetPrivate(&pixmap->devPrivates, &amdgpu_pixmap_index);
51}
52
53static inline void amdgpu_set_pixmap_private(PixmapPtr pixmap,
54					     struct amdgpu_pixmap *priv)
55{
56	dixSetPrivate(&pixmap->devPrivates, &amdgpu_pixmap_index, priv);
57}
58
59static inline Bool amdgpu_set_pixmap_bo(PixmapPtr pPix, struct amdgpu_buffer *bo)
60{
61	ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen);
62	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
63	struct amdgpu_pixmap *priv;
64
65	priv = amdgpu_get_pixmap_private(pPix);
66	if (!priv && !bo)
67		return TRUE;
68
69	if (priv) {
70		if (priv->bo) {
71			if (priv->bo == bo)
72				return TRUE;
73
74			amdgpu_bo_unref(&priv->bo);
75			priv->handle_valid = FALSE;
76		}
77
78		drmmode_fb_reference(pAMDGPUEnt->fd, &priv->fb, NULL);
79
80		if (!bo) {
81			free(priv);
82			priv = NULL;
83		}
84	}
85
86	if (bo) {
87		if (!priv) {
88			priv = calloc(1, sizeof(struct amdgpu_pixmap));
89			if (!priv)
90				return FALSE;
91		}
92		amdgpu_bo_ref(bo);
93		priv->bo = bo;
94	}
95
96	amdgpu_set_pixmap_private(pPix, priv);
97	return TRUE;
98}
99
100static inline struct amdgpu_buffer *amdgpu_get_pixmap_bo(PixmapPtr pPix)
101{
102	struct amdgpu_pixmap *priv;
103	priv = amdgpu_get_pixmap_private(pPix);
104	return priv ? priv->bo : NULL;
105}
106
107static inline struct drmmode_fb*
108amdgpu_fb_create(ScrnInfoPtr scrn, int drm_fd, uint32_t width, uint32_t height,
109		 uint32_t pitch, uint32_t handle)
110{
111	struct drmmode_fb *fb  = malloc(sizeof(*fb));
112
113	if (!fb)
114		return NULL;
115
116	fb->refcnt = 1;
117	if (drmModeAddFB(drm_fd, width, height, scrn->depth, scrn->bitsPerPixel,
118			 pitch, handle, &fb->handle) == 0)
119		return fb;
120
121	free(fb);
122	return NULL;
123}
124
125static inline struct drmmode_fb**
126amdgpu_pixmap_get_fb_ptr(PixmapPtr pix)
127{
128	ScrnInfoPtr scrn = xf86ScreenToScrn(pix->drawable.pScreen);
129	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
130
131	if (info->use_glamor) {
132		struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pix);
133
134		if (!priv)
135			return NULL;
136
137		return &priv->fb;
138	}
139
140	return NULL;
141}
142
143static inline struct drmmode_fb*
144amdgpu_pixmap_get_fb(PixmapPtr pix)
145{
146	struct drmmode_fb **fb_ptr = amdgpu_pixmap_get_fb_ptr(pix);
147	uint32_t handle;
148
149	if (fb_ptr && *fb_ptr)
150		return *fb_ptr;
151
152	if (amdgpu_pixmap_get_handle(pix, &handle)) {
153		ScrnInfoPtr scrn = xf86ScreenToScrn(pix->drawable.pScreen);
154		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
155
156		if (!fb_ptr)
157			fb_ptr = amdgpu_pixmap_get_fb_ptr(pix);
158
159		*fb_ptr = amdgpu_fb_create(scrn, pAMDGPUEnt->fd,
160					   pix->drawable.width,
161					   pix->drawable.height, pix->devKind,
162					   handle);
163	}
164
165	return fb_ptr ? *fb_ptr : NULL;
166}
167
168enum {
169	AMDGPU_CREATE_PIXMAP_DRI2    = 0x08000000,
170	AMDGPU_CREATE_PIXMAP_LINEAR  = 0x04000000,
171	AMDGPU_CREATE_PIXMAP_SCANOUT = 0x02000000,
172	AMDGPU_CREATE_PIXMAP_GTT     = 0x01000000,
173};
174
175extern Bool amdgpu_pixmap_init(ScreenPtr screen);
176
177#endif /* AMDGPU_PIXMAP_H */
178