Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 2010 LunarG Inc. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||
22 | * DEALINGS IN THE SOFTWARE. |
||
23 | * |
||
24 | * Authors: |
||
25 | * Chia-I Wu |
||
26 | */ |
||
27 | |||
28 | #include "pipe/p_screen.h" |
||
29 | #include "util/u_memory.h" |
||
30 | #include "util/u_rect.h" |
||
31 | #include "util/u_inlines.h" |
||
32 | #include "eglcurrent.h" |
||
33 | #include "egllog.h" |
||
34 | |||
35 | #include "native.h" |
||
36 | #include "egl_g3d.h" |
||
37 | #include "egl_g3d_image.h" |
||
38 | |||
39 | /** |
||
40 | * Reference and return the front left buffer of the native pixmap. |
||
41 | */ |
||
42 | static struct pipe_resource * |
||
43 | egl_g3d_reference_native_pixmap(_EGLDisplay *dpy, EGLNativePixmapType pix) |
||
44 | { |
||
45 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
46 | struct native_surface *nsurf; |
||
47 | struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS]; |
||
48 | enum native_attachment natt; |
||
49 | |||
50 | nsurf = gdpy->native->create_pixmap_surface(gdpy->native, pix, NULL); |
||
51 | if (!nsurf) |
||
52 | return NULL; |
||
53 | |||
54 | natt = NATIVE_ATTACHMENT_FRONT_LEFT; |
||
55 | if (!nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL)) |
||
56 | textures[natt] = NULL; |
||
57 | |||
58 | nsurf->destroy(nsurf); |
||
59 | |||
60 | return textures[natt]; |
||
61 | } |
||
62 | |||
63 | #ifdef EGL_MESA_drm_image |
||
64 | |||
65 | static struct pipe_resource * |
||
66 | egl_g3d_create_drm_buffer(_EGLDisplay *dpy, _EGLImage *img, |
||
67 | const EGLint *attribs) |
||
68 | { |
||
69 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
70 | struct pipe_screen *screen = gdpy->native->screen; |
||
71 | struct pipe_resource templ; |
||
72 | _EGLImageAttribs attrs; |
||
73 | EGLint format, valid_use; |
||
74 | |||
75 | if (_eglParseImageAttribList(&attrs, dpy, attribs) != EGL_SUCCESS) |
||
76 | return NULL; |
||
77 | |||
78 | if (attrs.Width <= 0 || attrs.Height <= 0) { |
||
79 | _eglLog(_EGL_DEBUG, "bad width or height (%dx%d)", |
||
80 | attrs.Width, attrs.Height); |
||
81 | return NULL; |
||
82 | } |
||
83 | |||
84 | switch (attrs.DRMBufferFormatMESA) { |
||
85 | case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: |
||
86 | format = PIPE_FORMAT_B8G8R8A8_UNORM; |
||
87 | break; |
||
88 | default: |
||
89 | _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", |
||
90 | attrs.DRMBufferFormatMESA); |
||
91 | return NULL; |
||
92 | break; |
||
93 | } |
||
94 | |||
95 | valid_use = EGL_DRM_BUFFER_USE_SCANOUT_MESA | |
||
96 | EGL_DRM_BUFFER_USE_SHARE_MESA | |
||
97 | EGL_DRM_BUFFER_USE_CURSOR_MESA; |
||
98 | if (attrs.DRMBufferUseMESA & ~valid_use) { |
||
99 | _eglLog(_EGL_DEBUG, "bad image use bit 0x%04x", |
||
100 | attrs.DRMBufferUseMESA); |
||
101 | return NULL; |
||
102 | } |
||
103 | |||
104 | memset(&templ, 0, sizeof(templ)); |
||
105 | templ.target = PIPE_TEXTURE_2D; |
||
106 | templ.format = format; |
||
107 | templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; |
||
108 | templ.width0 = attrs.Width; |
||
109 | templ.height0 = attrs.Height; |
||
110 | templ.depth0 = 1; |
||
111 | templ.array_size = 1; |
||
112 | |||
113 | /* |
||
114 | * XXX fix apps (e.g. wayland) and pipe drivers (e.g. i915) and remove the |
||
115 | * size check |
||
116 | */ |
||
117 | if ((attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA) && |
||
118 | attrs.Width >= 640 && attrs.Height >= 480) |
||
119 | templ.bind |= PIPE_BIND_SCANOUT; |
||
120 | if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA) |
||
121 | templ.bind |= PIPE_BIND_SHARED; |
||
122 | if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA) { |
||
123 | if (attrs.Width != 64 || attrs.Height != 64) |
||
124 | return NULL; |
||
125 | templ.bind |= PIPE_BIND_CURSOR; |
||
126 | } |
||
127 | |||
128 | return screen->resource_create(screen, &templ); |
||
129 | } |
||
130 | |||
131 | static struct pipe_resource * |
||
132 | egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, |
||
133 | _EGLImage *img, const EGLint *attribs) |
||
134 | { |
||
135 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
136 | _EGLImageAttribs attrs; |
||
137 | EGLint format; |
||
138 | struct native_buffer nbuf; |
||
139 | |||
140 | if (!dpy->Extensions.MESA_drm_image) |
||
141 | return NULL; |
||
142 | |||
143 | if (_eglParseImageAttribList(&attrs, dpy, attribs) != EGL_SUCCESS) |
||
144 | return NULL; |
||
145 | |||
146 | if (attrs.Width <= 0 || attrs.Height <= 0 || |
||
147 | attrs.DRMBufferStrideMESA <= 0) { |
||
148 | _eglLog(_EGL_DEBUG, "bad width, height, or stride (%dx%dx%d)", |
||
149 | attrs.Width, attrs.Height, attrs.DRMBufferStrideMESA); |
||
150 | return NULL; |
||
151 | } |
||
152 | |||
153 | switch (attrs.DRMBufferFormatMESA) { |
||
154 | case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: |
||
155 | format = PIPE_FORMAT_B8G8R8A8_UNORM; |
||
156 | break; |
||
157 | default: |
||
158 | _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", |
||
159 | attrs.DRMBufferFormatMESA); |
||
160 | return NULL; |
||
161 | break; |
||
162 | } |
||
163 | |||
164 | memset(&nbuf, 0, sizeof(nbuf)); |
||
165 | nbuf.type = NATIVE_BUFFER_DRM; |
||
166 | nbuf.u.drm.templ.target = PIPE_TEXTURE_2D; |
||
167 | nbuf.u.drm.templ.format = format; |
||
168 | nbuf.u.drm.templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; |
||
169 | nbuf.u.drm.templ.width0 = attrs.Width; |
||
170 | nbuf.u.drm.templ.height0 = attrs.Height; |
||
171 | nbuf.u.drm.templ.depth0 = 1; |
||
172 | nbuf.u.drm.templ.array_size = 1; |
||
173 | |||
174 | nbuf.u.drm.name = name; |
||
175 | nbuf.u.drm.stride = |
||
176 | attrs.DRMBufferStrideMESA * util_format_get_blocksize(format); |
||
177 | |||
178 | return gdpy->native->buffer->import_buffer(gdpy->native, &nbuf); |
||
179 | } |
||
180 | |||
181 | #endif /* EGL_MESA_drm_image */ |
||
182 | |||
183 | #ifdef EGL_WL_bind_wayland_display |
||
184 | |||
185 | static struct pipe_resource * |
||
186 | egl_g3d_reference_wl_buffer(_EGLDisplay *dpy, struct wl_buffer *buffer, |
||
187 | _EGLImage *img, const EGLint *attribs) |
||
188 | { |
||
189 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
190 | struct pipe_resource *resource = NULL, *tmp = NULL; |
||
191 | |||
192 | if (!gdpy->native->wayland_bufmgr) |
||
193 | return NULL; |
||
194 | |||
195 | tmp = gdpy->native->wayland_bufmgr->buffer_get_resource(gdpy->native, buffer); |
||
196 | |||
197 | pipe_resource_reference(&resource, tmp); |
||
198 | |||
199 | return resource; |
||
200 | } |
||
201 | |||
202 | #endif /* EGL_WL_bind_wayland_display */ |
||
203 | |||
204 | #ifdef EGL_ANDROID_image_native_buffer |
||
205 | |||
206 | static struct pipe_resource * |
||
207 | egl_g3d_reference_android_native_buffer(_EGLDisplay *dpy, |
||
208 | struct ANativeWindowBuffer *buf) |
||
209 | { |
||
210 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
211 | struct native_buffer nbuf; |
||
212 | |||
213 | memset(&nbuf, 0, sizeof(nbuf)); |
||
214 | nbuf.type = NATIVE_BUFFER_ANDROID; |
||
215 | nbuf.u.android = buf; |
||
216 | |||
217 | return gdpy->native->buffer->import_buffer(gdpy->native, &nbuf); |
||
218 | } |
||
219 | |||
220 | #endif /* EGL_ANDROID_image_native_buffer */ |
||
221 | |||
222 | _EGLImage * |
||
223 | egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, |
||
224 | EGLenum target, EGLClientBuffer buffer, |
||
225 | const EGLint *attribs) |
||
226 | { |
||
227 | struct pipe_resource *ptex; |
||
228 | struct egl_g3d_image *gimg; |
||
229 | unsigned level = 0, layer = 0; |
||
230 | |||
231 | gimg = CALLOC_STRUCT(egl_g3d_image); |
||
232 | if (!gimg) { |
||
233 | _eglError(EGL_BAD_ALLOC, "eglCreateEGLImageKHR"); |
||
234 | return NULL; |
||
235 | } |
||
236 | |||
237 | if (!_eglInitImage(&gimg->base, dpy)) { |
||
238 | FREE(gimg); |
||
239 | return NULL; |
||
240 | } |
||
241 | |||
242 | switch (target) { |
||
243 | case EGL_NATIVE_PIXMAP_KHR: |
||
244 | ptex = egl_g3d_reference_native_pixmap(dpy, |
||
245 | (EGLNativePixmapType) buffer); |
||
246 | break; |
||
247 | #ifdef EGL_MESA_drm_image |
||
248 | case EGL_DRM_BUFFER_MESA: |
||
249 | ptex = egl_g3d_reference_drm_buffer(dpy, |
||
250 | (EGLint) pointer_to_intptr(buffer), &gimg->base, attribs); |
||
251 | break; |
||
252 | #endif |
||
253 | #ifdef EGL_WL_bind_wayland_display |
||
254 | case EGL_WAYLAND_BUFFER_WL: |
||
255 | ptex = egl_g3d_reference_wl_buffer(dpy, |
||
256 | (struct wl_buffer *) buffer, &gimg->base, attribs); |
||
257 | break; |
||
258 | #endif |
||
259 | #ifdef EGL_ANDROID_image_native_buffer |
||
260 | case EGL_NATIVE_BUFFER_ANDROID: |
||
261 | ptex = egl_g3d_reference_android_native_buffer(dpy, |
||
262 | (struct ANativeWindowBuffer *) buffer); |
||
263 | break; |
||
264 | #endif |
||
265 | default: |
||
266 | ptex = NULL; |
||
267 | break; |
||
268 | } |
||
269 | |||
270 | if (!ptex) { |
||
271 | FREE(gimg); |
||
272 | return NULL; |
||
273 | } |
||
274 | |||
275 | if (level > ptex->last_level) { |
||
276 | _eglError(EGL_BAD_MATCH, "eglCreateEGLImageKHR"); |
||
277 | pipe_resource_reference(&gimg->texture, NULL); |
||
278 | FREE(gimg); |
||
279 | return NULL; |
||
280 | } |
||
281 | if (layer >= (u_minify(ptex->depth0, level) + ptex->array_size - 1)) { |
||
282 | _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); |
||
283 | pipe_resource_reference(&gimg->texture, NULL); |
||
284 | FREE(gimg); |
||
285 | return NULL; |
||
286 | } |
||
287 | |||
288 | /* transfer the ownership to the image */ |
||
289 | gimg->texture = ptex; |
||
290 | gimg->level = level; |
||
291 | gimg->layer = layer; |
||
292 | |||
293 | return &gimg->base; |
||
294 | } |
||
295 | |||
296 | EGLBoolean |
||
297 | egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) |
||
298 | { |
||
299 | struct egl_g3d_image *gimg = egl_g3d_image(img); |
||
300 | |||
301 | pipe_resource_reference(&gimg->texture, NULL); |
||
302 | FREE(gimg); |
||
303 | |||
304 | return EGL_TRUE; |
||
305 | } |
||
306 | |||
307 | _EGLImage * |
||
308 | egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, |
||
309 | const EGLint *attribs) |
||
310 | { |
||
311 | struct egl_g3d_image *gimg; |
||
312 | struct pipe_resource *ptex; |
||
313 | |||
314 | gimg = CALLOC_STRUCT(egl_g3d_image); |
||
315 | if (!gimg) { |
||
316 | _eglError(EGL_BAD_ALLOC, "eglCreateDRMImageKHR"); |
||
317 | return NULL; |
||
318 | } |
||
319 | |||
320 | if (!_eglInitImage(&gimg->base, dpy)) { |
||
321 | FREE(gimg); |
||
322 | return NULL; |
||
323 | } |
||
324 | |||
325 | #ifdef EGL_MESA_drm_image |
||
326 | ptex = egl_g3d_create_drm_buffer(dpy, &gimg->base, attribs); |
||
327 | #else |
||
328 | ptex = NULL; |
||
329 | #endif |
||
330 | if (!ptex) { |
||
331 | FREE(gimg); |
||
332 | return NULL; |
||
333 | } |
||
334 | |||
335 | /* transfer the ownership to the image */ |
||
336 | gimg->texture = ptex; |
||
337 | gimg->level = 0; |
||
338 | gimg->layer = 0; |
||
339 | |||
340 | return &gimg->base; |
||
341 | } |
||
342 | |||
343 | EGLBoolean |
||
344 | egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, |
||
345 | EGLint *name, EGLint *handle, EGLint *stride) |
||
346 | { |
||
347 | struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
||
348 | struct egl_g3d_image *gimg = egl_g3d_image(img); |
||
349 | struct native_buffer nbuf; |
||
350 | |||
351 | if (!dpy->Extensions.MESA_drm_image) |
||
352 | return EGL_FALSE; |
||
353 | |||
354 | memset(&nbuf, 0, sizeof(nbuf)); |
||
355 | nbuf.type = NATIVE_BUFFER_DRM; |
||
356 | if (name) |
||
357 | nbuf.u.drm.templ.bind |= PIPE_BIND_SHARED; |
||
358 | |||
359 | if (!gdpy->native->buffer->export_buffer(gdpy->native, |
||
360 | gimg->texture, &nbuf)) |
||
361 | return EGL_FALSE; |
||
362 | |||
363 | if (name) |
||
364 | *name = nbuf.u.drm.name; |
||
365 | if (handle) |
||
366 | *handle = nbuf.u.drm.handle; |
||
367 | if (stride) |
||
368 | *stride = nbuf.u.drm.stride; |
||
369 | |||
370 | return EGL_TRUE; |
||
371 | }=>=>=>=>=>><> |