1#include "frontend/drm_driver.h"
2#include "i915_drm_winsys.h"
3#include "util/u_memory.h"
4
5#include "drm-uapi/i915_drm.h"
6
7static char *i915_drm_type_to_name(enum i915_winsys_buffer_type type)
8{
9   char *name;
10
11   if (type == I915_NEW_TEXTURE) {
12      name = "gallium3d_texture";
13   } else if (type == I915_NEW_VERTEX) {
14      name = "gallium3d_vertex";
15   } else if (type == I915_NEW_SCANOUT) {
16      name = "gallium3d_scanout";
17   } else {
18      assert(0);
19      name = "gallium3d_unknown";
20   }
21
22   return name;
23}
24
25static struct i915_winsys_buffer *
26i915_drm_buffer_create(struct i915_winsys *iws,
27                        unsigned size,
28                        enum i915_winsys_buffer_type type)
29{
30   struct i915_drm_buffer *buf = CALLOC_STRUCT(i915_drm_buffer);
31   struct i915_drm_winsys *idws = i915_drm_winsys(iws);
32
33   if (!buf)
34      return NULL;
35
36   buf->magic = 0xDEAD1337;
37   buf->flinked = false;
38   buf->flink = 0;
39
40   buf->bo = drm_intel_bo_alloc(idws->gem_manager,
41                                i915_drm_type_to_name(type), size, 0);
42
43   if (!buf->bo)
44      goto err;
45
46   return (struct i915_winsys_buffer *)buf;
47
48err:
49   assert(0);
50   FREE(buf);
51   return NULL;
52}
53
54static struct i915_winsys_buffer *
55i915_drm_buffer_create_tiled(struct i915_winsys *iws,
56                             unsigned *stride, unsigned height,
57                             enum i915_winsys_buffer_tile *tiling,
58                             enum i915_winsys_buffer_type type)
59{
60   struct i915_drm_buffer *buf = CALLOC_STRUCT(i915_drm_buffer);
61   struct i915_drm_winsys *idws = i915_drm_winsys(iws);
62   unsigned long pitch = 0;
63   uint32_t tiling_mode = *tiling;
64
65   if (!buf)
66      return NULL;
67
68   buf->magic = 0xDEAD1337;
69   buf->flinked = false;
70   buf->flink = 0;
71
72   buf->bo = drm_intel_bo_alloc_tiled(idws->gem_manager,
73                                      i915_drm_type_to_name(type),
74                                      *stride, height, 1,
75                                      &tiling_mode, &pitch, 0);
76
77   if (!buf->bo)
78      goto err;
79
80   *stride = pitch;
81   *tiling = tiling_mode;
82   return (struct i915_winsys_buffer *)buf;
83
84err:
85   assert(0);
86   FREE(buf);
87   return NULL;
88}
89
90static struct i915_winsys_buffer *
91i915_drm_buffer_from_handle(struct i915_winsys *iws,
92                            struct winsys_handle *whandle,
93                            unsigned height,
94                            enum i915_winsys_buffer_tile *tiling,
95                            unsigned *stride)
96{
97   struct i915_drm_winsys *idws = i915_drm_winsys(iws);
98   struct i915_drm_buffer *buf;
99   uint32_t tile = 0, swizzle = 0;
100
101   if ((whandle->type != WINSYS_HANDLE_TYPE_SHARED) && (whandle->type != WINSYS_HANDLE_TYPE_FD))
102      return NULL;
103
104   if (whandle->offset != 0)
105      return NULL;
106
107   buf = CALLOC_STRUCT(i915_drm_buffer);
108   if (!buf)
109      return NULL;
110
111   buf->magic = 0xDEAD1337;
112
113   if (whandle->type == WINSYS_HANDLE_TYPE_SHARED)
114       buf->bo = drm_intel_bo_gem_create_from_name(idws->gem_manager, "gallium3d_from_handle", whandle->handle);
115   else if (whandle->type == WINSYS_HANDLE_TYPE_FD) {
116       int fd = (int) whandle->handle;
117       buf->bo = drm_intel_bo_gem_create_from_prime(idws->gem_manager, fd, height * whandle->stride);
118   }
119
120   buf->flinked = true;
121   buf->flink = whandle->handle;
122
123   if (!buf->bo)
124      goto err;
125
126   drm_intel_bo_get_tiling(buf->bo, &tile, &swizzle);
127
128   *stride = whandle->stride;
129   *tiling = tile;
130
131   return (struct i915_winsys_buffer *)buf;
132
133err:
134   FREE(buf);
135   return NULL;
136}
137
138static bool
139i915_drm_buffer_get_handle(struct i915_winsys *iws,
140                            struct i915_winsys_buffer *buffer,
141                            struct winsys_handle *whandle,
142                            unsigned stride)
143{
144   struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
145
146   if (whandle->type == WINSYS_HANDLE_TYPE_SHARED) {
147      if (!buf->flinked) {
148         if (drm_intel_bo_flink(buf->bo, &buf->flink))
149            return false;
150         buf->flinked = true;
151      }
152
153      whandle->handle = buf->flink;
154   } else if (whandle->type == WINSYS_HANDLE_TYPE_KMS) {
155      whandle->handle = buf->bo->handle;
156   } else if (whandle->type == WINSYS_HANDLE_TYPE_FD) {
157      int fd;
158
159      if (drm_intel_bo_gem_export_to_prime(buf->bo, &fd))
160         return false;
161      whandle->handle = fd;
162   } else {
163      assert(!"unknown usage");
164      return false;
165   }
166
167   whandle->stride = stride;
168   return true;
169}
170
171static void *
172i915_drm_buffer_map(struct i915_winsys *iws,
173                     struct i915_winsys_buffer *buffer,
174                     bool write)
175{
176   struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
177   drm_intel_bo *bo = intel_bo(buffer);
178   int ret = 0;
179
180   assert(bo);
181
182   if (buf->map_count)
183      goto out;
184
185   ret = drm_intel_gem_bo_map_gtt(bo);
186
187   buf->ptr = bo->virtual;
188
189   assert(ret == 0);
190out:
191   if (ret)
192      return NULL;
193
194   buf->map_count++;
195   return buf->ptr;
196}
197
198static void
199i915_drm_buffer_unmap(struct i915_winsys *iws,
200                       struct i915_winsys_buffer *buffer)
201{
202   struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
203
204   if (--buf->map_count)
205      return;
206
207   drm_intel_gem_bo_unmap_gtt(intel_bo(buffer));
208}
209
210static int
211i915_drm_buffer_write(struct i915_winsys *iws,
212                       struct i915_winsys_buffer *buffer,
213                       size_t offset,
214                       size_t size,
215                       const void *data)
216{
217   struct i915_drm_buffer *buf = i915_drm_buffer(buffer);
218
219   return drm_intel_bo_subdata(buf->bo, offset, size, (void*)data);
220}
221
222static void
223i915_drm_buffer_destroy(struct i915_winsys *iws,
224                         struct i915_winsys_buffer *buffer)
225{
226   drm_intel_bo_unreference(intel_bo(buffer));
227
228#ifdef DEBUG
229   i915_drm_buffer(buffer)->magic = 0;
230   i915_drm_buffer(buffer)->bo = NULL;
231#endif
232
233   FREE(buffer);
234}
235
236static bool
237i915_drm_buffer_is_busy(struct i915_winsys *iws,
238                        struct i915_winsys_buffer *buffer)
239{
240   struct i915_drm_buffer* i915_buffer = i915_drm_buffer(buffer);
241   if (!i915_buffer)
242      return false;
243   return drm_intel_bo_busy(i915_buffer->bo);
244}
245
246
247void
248i915_drm_winsys_init_buffer_functions(struct i915_drm_winsys *idws)
249{
250   idws->base.buffer_create = i915_drm_buffer_create;
251   idws->base.buffer_create_tiled = i915_drm_buffer_create_tiled;
252   idws->base.buffer_from_handle = i915_drm_buffer_from_handle;
253   idws->base.buffer_get_handle = i915_drm_buffer_get_handle;
254   idws->base.buffer_map = i915_drm_buffer_map;
255   idws->base.buffer_unmap = i915_drm_buffer_unmap;
256   idws->base.buffer_write = i915_drm_buffer_write;
257   idws->base.buffer_destroy = i915_drm_buffer_destroy;
258   idws->base.buffer_is_busy = i915_drm_buffer_is_busy;
259}
260