st/dri: move some image functions to dri_helpers.c
[mesa.git] / src / gallium / state_trackers / dri / dri_helpers.c
1 /*
2 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS 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 #include <dlfcn.h>
24 #include "util/u_memory.h"
25 #include "pipe/p_screen.h"
26 #include "state_tracker/st_texture.h"
27 #include "state_tracker/st_context.h"
28 #include "main/texobj.h"
29
30 #include "dri_helpers.h"
31
32 static bool
33 dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen)
34 {
35 return screen->opencl_dri_event_add_ref &&
36 screen->opencl_dri_event_release &&
37 screen->opencl_dri_event_wait &&
38 screen->opencl_dri_event_get_fence;
39 }
40
41 static bool
42 dri2_load_opencl_interop(struct dri_screen *screen)
43 {
44 #if defined(RTLD_DEFAULT)
45 bool success;
46
47 mtx_lock(&screen->opencl_func_mutex);
48
49 if (dri2_is_opencl_interop_loaded_locked(screen)) {
50 mtx_unlock(&screen->opencl_func_mutex);
51 return true;
52 }
53
54 screen->opencl_dri_event_add_ref =
55 dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref");
56 screen->opencl_dri_event_release =
57 dlsym(RTLD_DEFAULT, "opencl_dri_event_release");
58 screen->opencl_dri_event_wait =
59 dlsym(RTLD_DEFAULT, "opencl_dri_event_wait");
60 screen->opencl_dri_event_get_fence =
61 dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence");
62
63 success = dri2_is_opencl_interop_loaded_locked(screen);
64 mtx_unlock(&screen->opencl_func_mutex);
65 return success;
66 #else
67 return false;
68 #endif
69 }
70
71 struct dri2_fence {
72 struct dri_screen *driscreen;
73 struct pipe_fence_handle *pipe_fence;
74 void *cl_event;
75 };
76
77 static unsigned dri2_fence_get_caps(__DRIscreen *_screen)
78 {
79 struct dri_screen *driscreen = dri_screen(_screen);
80 struct pipe_screen *screen = driscreen->base.screen;
81 unsigned caps = 0;
82
83 if (screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
84 caps |= __DRI_FENCE_CAP_NATIVE_FD;
85
86 return caps;
87 }
88
89 static void *
90 dri2_create_fence(__DRIcontext *_ctx)
91 {
92 struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
93 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
94
95 if (!fence)
96 return NULL;
97
98 ctx->flush(ctx, &fence->pipe_fence, 0);
99
100 if (!fence->pipe_fence) {
101 FREE(fence);
102 return NULL;
103 }
104
105 fence->driscreen = dri_screen(_ctx->driScreenPriv);
106 return fence;
107 }
108
109 static void *
110 dri2_create_fence_fd(__DRIcontext *_ctx, int fd)
111 {
112 struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
113 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
114
115 if (fd == -1) {
116 /* exporting driver created fence, flush: */
117 ctx->flush(ctx, &fence->pipe_fence,
118 PIPE_FLUSH_DEFERRED | PIPE_FLUSH_FENCE_FD);
119 } else {
120 /* importing a foreign fence fd: */
121 ctx->create_fence_fd(ctx, &fence->pipe_fence, fd);
122 }
123 if (!fence->pipe_fence) {
124 FREE(fence);
125 return NULL;
126 }
127
128 fence->driscreen = dri_screen(_ctx->driScreenPriv);
129 return fence;
130 }
131
132 static int
133 dri2_get_fence_fd(__DRIscreen *_screen, void *_fence)
134 {
135 struct dri_screen *driscreen = dri_screen(_screen);
136 struct pipe_screen *screen = driscreen->base.screen;
137 struct dri2_fence *fence = (struct dri2_fence*)_fence;
138
139 return screen->fence_get_fd(screen, fence->pipe_fence);
140 }
141
142 static void *
143 dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event)
144 {
145 struct dri_screen *driscreen = dri_screen(_screen);
146 struct dri2_fence *fence;
147
148 if (!dri2_load_opencl_interop(driscreen))
149 return NULL;
150
151 fence = CALLOC_STRUCT(dri2_fence);
152 if (!fence)
153 return NULL;
154
155 fence->cl_event = (void*)cl_event;
156
157 if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) {
158 free(fence);
159 return NULL;
160 }
161
162 fence->driscreen = driscreen;
163 return fence;
164 }
165
166 static void
167 dri2_destroy_fence(__DRIscreen *_screen, void *_fence)
168 {
169 struct dri_screen *driscreen = dri_screen(_screen);
170 struct pipe_screen *screen = driscreen->base.screen;
171 struct dri2_fence *fence = (struct dri2_fence*)_fence;
172
173 if (fence->pipe_fence)
174 screen->fence_reference(screen, &fence->pipe_fence, NULL);
175 else if (fence->cl_event)
176 driscreen->opencl_dri_event_release(fence->cl_event);
177 else
178 assert(0);
179
180 FREE(fence);
181 }
182
183 static GLboolean
184 dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags,
185 uint64_t timeout)
186 {
187 struct dri2_fence *fence = (struct dri2_fence*)_fence;
188 struct dri_screen *driscreen = fence->driscreen;
189 struct pipe_screen *screen = driscreen->base.screen;
190
191 /* No need to flush. The context was flushed when the fence was created. */
192
193 if (fence->pipe_fence)
194 return screen->fence_finish(screen, NULL, fence->pipe_fence, timeout);
195 else if (fence->cl_event) {
196 struct pipe_fence_handle *pipe_fence =
197 driscreen->opencl_dri_event_get_fence(fence->cl_event);
198
199 if (pipe_fence)
200 return screen->fence_finish(screen, NULL, pipe_fence, timeout);
201 else
202 return driscreen->opencl_dri_event_wait(fence->cl_event, timeout);
203 }
204 else {
205 assert(0);
206 return false;
207 }
208 }
209
210 static void
211 dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags)
212 {
213 struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
214 struct dri2_fence *fence = (struct dri2_fence*)_fence;
215
216 if (ctx->fence_server_sync)
217 ctx->fence_server_sync(ctx, fence->pipe_fence);
218 }
219
220 const __DRI2fenceExtension dri2FenceExtension = {
221 .base = { __DRI2_FENCE, 2 },
222
223 .create_fence = dri2_create_fence,
224 .get_fence_from_cl_event = dri2_get_fence_from_cl_event,
225 .destroy_fence = dri2_destroy_fence,
226 .client_wait_sync = dri2_client_wait_sync,
227 .server_wait_sync = dri2_server_wait_sync,
228 .get_capabilities = dri2_fence_get_caps,
229 .create_fence_fd = dri2_create_fence_fd,
230 .get_fence_fd = dri2_get_fence_fd,
231 };
232
233 __DRIimage *
234 dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
235 {
236 const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
237 __DRIimage *img;
238
239 if (!loader->lookupEGLImage)
240 return NULL;
241
242 img = loader->lookupEGLImage(screen->sPriv,
243 handle, screen->sPriv->loaderPrivate);
244
245 return img;
246 }
247
248 __DRIimage *
249 dri2_create_image_from_renderbuffer(__DRIcontext *context,
250 int renderbuffer, void *loaderPrivate)
251 {
252 struct dri_context *ctx = dri_context(context);
253
254 if (!ctx->st->get_resource_for_egl_image)
255 return NULL;
256
257 /* TODO */
258 return NULL;
259 }
260
261 void
262 dri2_destroy_image(__DRIimage *img)
263 {
264 pipe_resource_reference(&img->texture, NULL);
265 FREE(img);
266 }
267
268
269 __DRIimage *
270 dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
271 int depth, int level, unsigned *error,
272 void *loaderPrivate)
273 {
274 __DRIimage *img;
275 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
276 struct gl_texture_object *obj;
277 struct pipe_resource *tex;
278 GLuint face = 0;
279
280 obj = _mesa_lookup_texture(ctx, texture);
281 if (!obj || obj->Target != target) {
282 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
283 return NULL;
284 }
285
286 tex = st_get_texobj_resource(obj);
287 if (!tex) {
288 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
289 return NULL;
290 }
291
292 if (target == GL_TEXTURE_CUBE_MAP)
293 face = depth;
294
295 _mesa_test_texobj_completeness(ctx, obj);
296 if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
297 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
298 return NULL;
299 }
300
301 if (level < obj->BaseLevel || level > obj->_MaxLevel) {
302 *error = __DRI_IMAGE_ERROR_BAD_MATCH;
303 return NULL;
304 }
305
306 if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
307 *error = __DRI_IMAGE_ERROR_BAD_MATCH;
308 return NULL;
309 }
310
311 img = CALLOC_STRUCT(__DRIimageRec);
312 if (!img) {
313 *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
314 return NULL;
315 }
316
317 img->level = level;
318 img->layer = depth;
319 img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
320
321 img->loader_private = loaderPrivate;
322
323 if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) {
324 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
325 free(img);
326 return NULL;
327 }
328
329 pipe_resource_reference(&img->texture, tex);
330
331 *error = __DRI_IMAGE_ERROR_SUCCESS;
332 return img;
333 }
334
335 /* vim: set sw=3 ts=8 sts=3 expandtab: */